Buenas prácticas de revisión de código (o Code Review)
Por Martín Olivera*
No importa en qué lenguaje programes, la revisión de código es una actividad insustituible del proceso de desarrollo de software. Si bien a algunes no les gusta hacerlo, nos permite aprender aquello que no sabemos. Así, la revisión de código como práctica habitual es un excelente - y sencillo - modo de formación continua en los equipos de trabajo.
POR QUÉ hacer Code Review
La explicación del manual nos dirá que mejora la calidad, la mantenibilidad y la homogeneización del código fuente. Veamos ahora los otros "por qué":
- Hasta el más genio se equivoca: una lectura apurada del requerimiento, una condición negada demasiadas veces, un mal día o una mala noche, un malestar de salud física o mental nos sucede a todes. Nadie es perfecto y hasta les programadores somos humanes y podemos equivocarnos.
- Los requerimientos no siempre son lo suficientemente claros: muchas veces suponemos cierta interpretación al programar, que a otra persona le despierta dudas y tal vez habría que preguntar o aclarar mejor algún detalle en el requerimiento.
- Es una excelente forma de enseñar y aprender a programar en equipo.
QUÉ revisar
Lo ideal sería revisar todo, pero la calidad deseada del producto es la que va a definir las premisas sobre la revisión requerida para determinado software. En base a mi experiencia algunas de las cosas en las que deben enfocarse una primera revisión de código son:
- Objetivo funcional: revisar el requerimiento funcional y al menos chequear que superficialmente el código aplique sobre el requerimiento solicitado. Igual, esto nunca remplazará a las pruebas funcionales, sean manuales o automatizadas.
- Nomenclaturas y convenciones: verificar que se cumplan los estilos del lenguaje y del proyecto; chequear guías de estilo particular si se hubieran acordado; que se aplique correctamente la nomenclatura, los case correctos, cómo nombrar las variables, funciones, métodos, clases... Lo que sea, tanto en formato como en adecuación al glosario específico, que no haya errores de tipeo (typos). Básicamente esto hace al código más legible y mantenible.
- Lógica y algoritmia: Esto puede variar mucho según el lenguaje de programación; pero suelen ser un punto de confusión las lógicas de control, en particular cuando se anidan condiciones en código spaghetti o se utilizan algoritmos tomados de algún otro sitio sin conocer bien los detalles de aplicación (¿copiar código de otros sitios? ¿quién hace eso?).
- Manejo de errores: Les programadores somos por naturaleza optimistas (del mismo modo que les testers suelen ser pesimistas). Un buena revisión de código debe sospechar que todo va a salir mal: ¿y si los parámetros no tienen los valores esperados? ¿Y si los recursos necesarios no están disponibles (archivos, servicios externos, bases de datos)? Así validamos cómo reaccionaría nuestro código ante esos sucesos inesperadamente frecuentes en la vida real.
- Mejoras conceptuales: Cuando el revisor tiene mayor experiencia que el autor del código; es posible que proponga otra forma de resolver las cosas, algoritmos, patrones de diseño, etc. A veces hay complejidades derivadas del asincronismo, de la concurrencia, del manejo de datos, formatos o de la memoria, o cualquier otra circunstancia. En esos casos, comentar con el uso del ejemplo concreto, mostrando cómo se haría y las ventajas obtenidas, es una excelente fuente de aprendizaje compartido.
CUÁNDO Y CUÁNTO revisar
Incluir la revisión de código en el proceso de desarrollo varía mucho de acuerdo al tamaño de nuestros sistemas y de la cantidad de programadores participantes. Se pueden mencionar herramientas y procesos, pero cada equipo deberá encontrar los métodos más adecuados a su propio proceso de trabajo.
Una de las formas más comunes es hacerlo durante el proceso de integración de código utilizando los sistemas de control de versiones (VCS como git, etc.); por ejemplo, en el flujo de merges de código, cuando se acepta una pieza de código, se debería hacer una revisión. En procesos que usen gitflow con feature branch, se puede hacer code review en el merge request cuando se requiera integrar el feature al branch de desarrollo o de release.
La profundidad de la revisión y el tiempo de retrabajo en correcciones es algo que cada equipo deberá autorregular ya que lo mejor es enemigo de lo bueno y a veces es necesario aceptar un código que no sea óptimo a la luz de otras circunstancias. Lo importante sería definir en cada equipo qué tipo de revisiones son obligatorias y cuáles opcionales, o si hay que considerar niveles de criticidad sobre los cambios que se solicitan ante una revisión de pulgar abajo.
CÓMO revisar
Prácticamente todos los sistemas de control de versiones como github, gitlab, etc. tienen visualizadores específicos de revisión liviana para los merge request que nos permiten identificar fácilmente los cambios entregados entre una versión de código y otra. Asimismo, en esas herramientas se pueden poner requisitos como la cantidad de revisores que deben aprobarlo, incluso entre grupos con diferentes categorías o seniorities.
Hay que tener en cuenta que para que el proceso de revisión sea eficaz debería hacerse frecuentemente y no en grandes cantidades de código. Por un lado, es más fácil encontrar problemas si los cambios son pequeños, y por otro, así podemos detectar inconvenientes en el desarrollo que no se propaguen hacia funcionalidades o soluciones más completas que luego cueste desanudar. Si una funcionalidad es compleja, es recomendable ir haciendo entregas parciales y la revisión de código en cada entrega. Aún cuando no esté toda la funcionalidad programada, permitirá detectar errores de interpretación o de programación más tempranamente.
También existen herramientas que ayudan a programadores y revisores a automatizar parte de estas tareas de revisión en lo que se refiere a estilos de codificación o errores comunes. Las mismas se pueden incorporar tanto en las IDEs de desarrollo como sobre los VCS que integran el código y facilitan identificar problemas comunes o garantizar estilos y requisitos deseados en el código, como SonarQube, PMD y otras similares.
Además, para les fanáticos del Code Review hay herramientas más sofisticadas y completas que podrán buscar y probar como Gerrit, Phabricator, Crucible y muchas más, cada maestrito con su librito...
La revisión de código como método de aprendizaje
En mis años de programador aprendí que la revisión de código es una de las formas más simples y eficaces de enseñar y aprender a programar en la vida diaria ya que se da de modo natural, progresivo, adecuado al contexto y es individual y grupal a la vez. Personalmente, creo que es la mejor forma de enseñar a programar.
Hay algunas premisas que es necesario que aclarar para esto. La revisión debe hacerse a conciencia y ser valorada por el equipo y los líderes técnicos; y la intención de criticar y ser criticado no debe confundirse con una evaluación del trabajador o de su capacidad, sino con una práctica habitual de la labor de un programador, ya que por nuestra tarea es lo más lógico y sano que siempre estemos aprendiendo cosas nuevas.
Una buena forma de hacerlo es de manera sincrónica. El pair-programming es muy bonito en teoría, pero es una falacia en la práctica en tiempos donde las empresas requieren un programador "full-stack" para que haga el trabajo de dos o tres... Se pueden dejar comentarios y respuestas sobre la herramienta de revisión de código que sean específicos, claros y, si es posible, con ejemplos de cómo algo se podría escribir mejor (de modo que no sólo sirva para mejorar el software sino también para enseñar a todos los que están observando las revisiones en cualquier momento). Incluso puede haber debates muy intersantes sobre distintas formas de resolver algo en los que todas las partes aprendan.
PARA QUÉ NO SIRVE el Code Review
Como detalle final, pero no menor, si bien considero que la revisión de código debe incluirse SIEMPRE dentro del proceso de desarrollo de software; es fundamental aclarar que dicha revisión no reemplaza el chequeo funcional del desarrollador, ni las pruebas unitarias, ni las pruebas de integración, ni las pruebas de regresión, ni las pruebas funcionales, ni las pruebas automatizadas. Básicamente, revisar el código no evita que haya que probar el software de todas las maneras posibles.
*Arquitecto de Software - Miembro del Consejo Directivo de AGC