“Nada puede ser tan útil (valioso) como un comentario puesto en el lugar correcto” . Esta frase pertenece a Robert C Martin, autor de Clean Code.
Existen comentarios denominados “buenos”. Son aquellos que necesitas, por ejemplo, para entender por qué se realizó cierto cambio en su día, puede ser porque tú no estabas presente, o ni siquiera formabas parte del equipo de desarrollo en ese momento.
Pero también tenemos la cruz de la moneda, y claro, existen comentarios llamados “malos”. Son aquellos que intentan explicar un código que ya de por sí está mal escrito. El código debería ser autoexplicativo, hablar por sí mismo y darte todas las respuestas que necesitas cuando lo estás leyendo.
La línea de separación entre ambos tipos de comentarios es muy fina. Es cierto que tener buenos comentarios ayuda y mucho. También emplear técnicas como diff debugging o de revisión de código ayudan a mantener nuestro software en perfecto orden. Pero hay una operación que dentro de los equipos de desarrollo se realiza miles de veces cada día: check-in.
¿Qué pasaría si utilizáramos el check-in como una herramienta más que nos ayudara a documentar el código que desarrollamos? ¿Qué pasaría si nuestros checkins contasen una historia?
La técnica que se describe en este post, no sólo es buena cómo método de auto-documentación del código sino también sirve para captar la manera en la que en general el equipo trabaja. Además es un buen modo para enseñar a las nuevas incorporaciones dentro del equipo, las técnicas que se emplean y lo que necesitan aprender.
El Problema: El Software Cambia
“Acepta el cambio para controlar el cambio”
El software siempre está cambiando. Cuanto más abierto de mente seas y mejor te adaptes a esta verdad, más control tendrás sobre el código.
Michael Feathers en su libro “Working on effectively with legacy code” explica estrategias para entender los mecanismos de por qué el software cambia: añadir nuevas características, arreglar fallos, mejorar el diseño.
En Plastic SCM trabajamos con el patrón de Rama-por-Tarea. Ponemos mucho hincapié en que los cambios hechos en las ramas tienen que estar revisados antes de proceder con la integración (merge). Esta revisión se puede hacer utilizando la vista de Diferencias, pero en ocasiones los cambios son tantos y tan pequeños que no es de gran utilidad.
Voy a tratar de explicarlo mejor con un caso práctico. Hace un par de semanas, estaba desarrollando una nueva funcionalidad que precisaba algunos cambios, sobre el código legado y nuevos ficheros que incorporaran nueva funcionalidad.
Esta nueva funcionalidad que se iba a desarrollar, necesitaba compartir código ya existente, con lo que la mayor parte del trabajo iba a consistir en hacer una refactorización del código para dejarlo preparado. Cuando terminé con los cambios, lo primero que hice fue ir a la vista de Diferencias para verificar todo lo que había hecho. En esta ocasión como los cambios eran pequeños, la vista de Diferencias me fue muy útil. Pero si hubiera muchísimos cambios, la vista de Diferencias no habría ayudado mucho porque el código tendría demasiados cambios, que no podría controlar.
“Inch-Pebble” Check-Ins
La traducción de “Inch Pebble” sería algo así como, “guijarros pequeños”. En español, guijarro ya trae de por sí el adjetivo pequeño. Definición de la RAE: Pequeño canto rodado. Quizá una traducción literal más adecuada sería algo como “micro cambios”. Pero sigamos con nuestro caso práctico.
Todo el mundo sabe lo que es un hito, y todo el mundo sabe que tenemos que alcanzar ciertos hitos en nuestro trabajo. Pero ¿qué ocurre si esta suposición fuera errónea?
¿Qué ocurre si en vez de un único hito, nos esforzamos en alcanzar muchos pequeños hitos?
En nuestro caso, marcar el camino con muchos guijarros. “Inch-Pebble” es un término acuñado por Johanna Rothman en el siguiente artículo. Lo he tomado prestado, para describir el proceso en el cual realizas check-in de tu código de manera frecuente, es decir con cada pequeño cambio haces un check-in. Usar la filosofía “Inch-Pebble” significa realizar check-in contínuos, y dejar fuera el realizar sólo uno o dos a lo largo del día.
Lo que pretendía lograr con esto es mostrar los cambios que había ido realizando en mi tarea, pero en vez de hacerlo con un fichero de log, lo quería hacer mostrando los check-in que había ido realizando simplemente cuando modificaba o añadía unas pocas líneas.
Las versiones modernas de los sistemas de control de versiones, se comportan de tal manera que agrupan todos los ficheros sobre los que hayas realizado check-in juntos. Cada una de estas agrupaciones lógicas se llama changeset, commit, transaction dependiendo de la nomenclatura que utilice tu sistema de control de versiones. De este modo, cada changeset ayudará por ejemplo a la persona que esté revisando el código a entender lo que se hizo, paso a paso, y por qué se hizo de ese modo.
Vamos a pasar a ver todo lo que hice. Trabajé usando una rama, que era sobre la que realizaba todos los cambios. Y lo que fui haciendo es lo siguiente:
- Moví un método privado desde la parte superior de la clase a la inferior, porque los privados deberían ir al final. Hice un changeset para describir este cambio.
- Moví código heredado a una clase nueva, y lo combiné con código nuevo. Hice un nuevo changeset para indicar este cambio.
- Creé un método nuevo para manejar parte de la nueva funcionalidad. Creé un nuevo changeset.
Continué con más pasos hasta finalizar. Cada uno de ellos, lo más atómico que podía y con su changeset correspondiente.
Ya he comentado que utilicé una sola rama para manejar estos cambios. ¿Qué significa esto? Significa sobre todo Libertad. Puedo hacer subidas de mi código a la rama, tan a menudo como quiera, sin preocuparme si rompo el build de la rama principal. El objetivo que tenía en mente era crear una secuencia documentada de cambios, de manera que si alguien se ponía a seguirla debería entender todos y cada uno de mis cambios. En realidad, era como estar grabando una película, escena a escena. Si lo piensas, es más fácil entender una refactorización paso a paso que mirar todo el proceso completo, cuando ha terminado.
En mi opinión, este proceso se puede aplicar no sólo en la refactorización, sino también cuando añadimos nuevas funcionalidades. De este modo, se va grabando el modo de trabajo y tan sólo los resultados finales, porque el proceso en sí mismo es la grabación que se ha realizado en el sistema de control de versiones. Se guarda la información importante que puede ser reutilizada por otros desarrolladores para entender cómo se trabaja en el equipo.
¿Cómo ayuda Plastic SCM en todo este proceso?
Lo primero es crear una rama, que es dónde vamos a trabajar y cambiamos el espacio de trabajo a esa rama.
Figure 1: Nueva rama
Ahora ya estamos listos para empezar a trabajar. Todos los cambios se harán en esta rama, y claro voy a hacer tantos check-in como necesite. Si vamos a la vista de Changeset, se pueden ir siguiendo de manera cómoda todos las actualizaciones que va teniendo la rama.
Figure 2: Vista de Changeset
Al final, si quiero saber cómo evolucionaron los cambios sobre el fichero original con el que empecé a trabajar, tendré la siguiente historia:
Figure 3: Vista de Cambios Pendientes
Figure 4: Historia de las Ramas (Inch-Pebble)
Revisando los cambios: tengo mi película gracias a los changeset
El hacer check-in con frecuencia, lo que produce es un conjunto de changeset que pueden ser revisados, uno a uno.
Figure 5: Plastic SCM -- Rama Selecciona
Figure 6: Vista de Menu Contextual
Si seleccionamos el menú contextual de la Vista de Menú, tenemos tres opciones disponibles:
- Ver los changeset de la rama
- Explorar los changeset de la rama
- Explorar el repositorio de la rama
Si seleccionamos la vista de Changeset de la rama, lo que podemos ver es lo siguiente:
Figure 7: Explorar los Changeset en la Rama (Plastic SCM GUI)
Seleccionando “Explorar Changeset” en la rama, obtenemos la siguiente pantalla:
Cada changeset contiene un conjunto de ficheros modificados, que afortunadamente están asociados a un comentario explicativo. Con las herramientas adecuadas, puedes inspeccionar de manera gráfica el contenido de cada changeset de modo que todos los pasos que tú has dado pueden ser seguidos por el resto de desarrolladores cómo si una cámara en vivo te estuviera grabando mientras estás desarrollando código.
Figure 8: Explorar cada Changeset en cada Rama
Conclusión
Todo el proceso que he descrito no es nuevo, ni mucho menos, pero espero que haya servido para entender la gran ayuda qué nos brinda el realizar pequeños check-in de manera continua. No sólo porque realizando cambios o desarrollo a pasos pequeños es más fácil ir construyendo el código que lo pruebe todo. Sino que también, sirve como documentación propia, de manera que cualquiera que se acerque a mirar esos cambios, pueda entender si son correctos o no. Piensa además lo importante que es esto cuando estás trabajando en proyectos enormes, donde cada día se mueven miles de líneas de código.
Las herramientas SCM pueden ayudar a grabar estas películas de autor, creadas a través de los changeset, siendo incluso más efectivas que utilizando las herramientas de revisión de código.