Que cualquier persona del equipo sea capaz de entregar el nivel deseado de calidad en el trabajo.

Esta es una meta ambiciosa y, a la vez, necesaria a la que debemos evolucionar. Esto se aplica tanto al desarrollo de software como a otros sectores o trabajos.

Una de las claves para conseguirlo es procedimentar o guionizar los trabajos a realizar. De forma que se extraigan las normas comunes que cualquier tarea debe incluir. Por ejemplo: un taller de coches en el que, al terminar cualquier labor, te lavan el coche. Independientemente de quién lo haga, debe completar esa tarea tanto si tiene que cambiar una rueda como si tiene que hacer un reglaje de válvulas. Si todo está debidamente guionizado y el proceso de onboarding empapa de esa cultura hasta al más junior, vamos a conseguir que incluso el becario que lleva dos semanas con nosotros entregue ese coche lavado como si lo hubiera arreglado el mecánico más experto de nuestro equipo.

Entrando ya en el sector del desarrollo de software, hoy traigo una herramienta muy útil para conseguir esto: una estrategia de checklist que deben ser seguidas tanto por el desarrollador como por el revisor al mergear código a ramas principales (desarroll, master, main…).

Yo trabajo con Gitlab y, por eso, el término que voy a utilizar durante todo este artículo es Merge Request. Si trabajas con GitHub, todo lo que voy a contar se aplica, con algunos matices y con alguna leve diferencia en implementación, a las Pull Request.

Inicialmente comencé a escribir una especie de manifiesto del desarrollador para el equipo que lidero. Este manifesto contenía una lista de tareas que siempre debían ser revisadas por el desarrollador antes de publicar una MR y ser revisada. Las tareas típicas y universales de las que hablo son tales como ¿has creado tests automatizados? Si se trata de un backend al que conectan diferentes clientes, ¿este cambio incluye un breaking change?. O, por ejemplo, si este cambio tiene base de datos, ¿está correctamente incluído el script de actualización en la herramienta de versionado de base de datos? ¿Es necesario backup de base de datos a la hora de desplegar este cambio? (Generalmente ya te aviso que la respuesta aquí suele ser que sí).

Todo eso está muy bien pero lo que pasaba es que nadie (ni siquiera yo…) leíamos ese documento y no se le hacía ni caso. Lo leímos un día, lo memorizamos (mejor dicho, creíamos haberlo memorizado) y esperábamos aplicarlo. Y claro, lo que pasaba es que al final no lo aplicábamos y unas veces nos acordábamos de indicar en la MR si el cambio era un breaking change y otras veces lo olvidábamos, derivando en problemas de que, en el despliegue, no se tenían en cuenta ciertos aspectos que aumentaban la probabilidad de fallo.

Se trata de cumplir varios objetivos:

    • Evitar despistes del desarrollador: ¿A quién no le ha pasado que tiene un cambio en su base de datos local y, como ya le funciona, se olvida de añadir el cambio a flyway?
    • Facilitar la labor del revisor: la tarea del revisor comienza siendo sencilla. Simplemente, revisa si es verdad que se cumplen los checks que el desarrollador ha marcado. Si todo está bien, ya puedes pasar a revisar la calidad del código y a trastear con la implementación para encontrar bugs. Sin embargo, si el desarrollador se ha olvidado algo (más a propósito o más inocentemente), ya significa que, al menos, parece que se ha dado más prisa de la debida. Así que lo primero es recordar que la plantilla debe estar completa. Esto les hará fijarse en los detalles.
    • Facilitar la obtención de información: cuando estás repasando features de las últimas 2 releases para conocer el histórico de algo, viene muy bien saber en qué partes se tocó o no se tocó la base de datos, cuáles contienen breaking changes y cuáles esconden mayor complejidad. Toda esta información es muy difícil de estandarizar si la descripción de una MR es simplemente una hoja en blanco en la que el desarrollador debe comunicar todo sobre ese cambio añadido.
    • Ser algo accesible y automático: no vale un documento pululando por el drive de la empresa que contenga las reglas básicas de desarrollo porque nadie lo va a leer. Tiene que ser algo que salga solo, por defecto y automatizado cada vez que se crea una MR.
    • Mantener actualizado el flujo de trabajo: no se trata solo de recordar que debes A, B y C. Sino que también hay que tener en cuenta que el flujo evoluciona con el equipo. Hoy es necesario A, B y C. Y mañana puede ser necesario eliminar C y sustituirlo por otra nueva. ¿Cómo nos damos cuenta? Pues porque llegará un desarrollador de turno y dirá «¿esto de aquí sigue siendo necesario? Porque en este caso no cumple» Y, si efectivamente no cumple porque algo ha cambiado y hay que actualizarlo, es fácil acordarse de actualizdo porque has cogido la costumbre de leerlo entero aunque lo tengas memorizado.
    • Adaptabilidad para cada proyecto: si bien antes he descrito que deben ser tareas universalizables para cada tarea, sí que cabe cierta personalización para cada proyecto. No es lo mismo un proyecto de una aplicación android que un backend que devuelve un simple json. En una app híbrida, por ejemplo, deberá incluirse un recordatorio de revisar el comportamiento de las páginas que se han editado tanto en web como en dispositivos móviles. Sin embargo, en el backed cobrará especial importancia el cumplimiento del contrato original de forma que sea compatible con todos los clientes o, incluso, retrocompatible. Cada proyecto tiene sus necesidades y se trata de adaptarlo al máximo.

Otro buen ejemplo que siempre me gusta utilizar es el de los pilotos de avión. Tienen su checklist (y, si no me equivoco, en papel) en el que siempre van haciendo cada tarea y marcándola como completada. Ni siquiera el piloto más veterano se atreve a saltarse el checklist y actuar por su cuenta. Con eso consiguen asegurar que, primero, nadie comete errores por despiste. Y, además, se arregla un problema que suelen tener este tipo de guías o manuales: que si no se utilizan, quedan desactualizadas. Nuestro manifesto quedó totalmente inútil porque, según fue evolucionando y mejorando el flujo de trabajo del equipo, no se actualizó (porque nadie lo leía y nade, por tanto, detectaba los fallos).

Crea la plantilla por defecto para tu equipo

Gitlab utiliza una especie de markdown sobrealimentado (ellos mismos lo llaman flavored markdown). Como cualquier markdown, podemos poner checks que se marcan o desmarcan haciendo click sin problema. Hasta ahí todo bien.

Ahora bien, no funciona adecuadamente si quieres tener varios checks en la misma línea.

Así que he diseñado una plantilla en modo tabla. De esta forma, podemos apoyarnos en la potencia que nos da un html básico para poder tener varios checks.

 

<table>
<thead>
<tr>
<th align="center">TASK NUMBER</th>
<th align="center">REVIEWER</th>
<th align="center">DEVELOPER</th>
<th align="center">TASK</th>
<th align="center">COMMENTS</th>
</tr>
</thead>
<tbody>
<tr><td align="center">1</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
I have written automated tests for this change
</td>
<td>

[//]: # (COMENTS FOR TASK 1 HERE)

</td></tr>
<tr><td align="center">2</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
I have updated documentation as needed
</td>
<td>

[//]: # (COMENTS FOR TASK 2 HERE)

</td></tr>
<tr><td align="center">3</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
I have updated flyway as needed (comment script version)
</td>
<td>

[//]: # (COMENTS FOR TASK 3 HERE)

</td></tr>
<tr><td align="center">4</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
I have checked if this changes contains breaking changes (link comment on gitlab task if it causes some incompatibilities)
</td>
<td>

[//]: # (COMENTS FOR TASK 4 HERE)

</td></tr>
<tr><td align="center">5</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
Is this merge request related to a frontend merge request? (If yes, link related merge request in comments)
</td>
<td>

[//]: # (COMENTS FOR TASK 5 HERE)

</td></tr>
<tr><td align="center">6</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
I have explained how to reproduce on issue comment (link to the comment)
</td>
<td>

[//]: # (COMENTS FOR TASK 6 HERE)

</td></tr>
<tr><td align="center">7</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
I have updated task status
</td>
<td>

[//]: # (COMENTS FOR TASK 7 HERE)

</td></tr>
<tr><td align="center">8</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
I have linked task with specific sprint
</td>
<td>

[//]: # (COMENTS FOR TASK 8 HERE)

</td></tr>
<tr><td align="center">9</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
I have mentioned this merge request on a comment on task
</td>
<td>

[//]: # (COMENTS FOR TASK 9 HERE)

</td></tr>
<tr><td align="center">10</td><td>

- [ ] done

</td><td>

- [ ] done

</td><td>
This merge request has been reviewed by another member of the team
</td>
<td>

[//]: # (COMENTS FOR TASK 10 HERE)

</td></tr>

</tbody>
</table>

El contenido de este archivo se visualizará aproximadamente así en cada una de las MRs nuevas que crees:

Tabla plantilla

Para que todo funcione bien, lo único que tienes que hacer es llamar a este archivo Default.md e insertarlo dentro de una carpeta llamada .gitlab/merge_request_templates en tu proyecto. Como muestra la imagen:

Ejemplo estructura de carpetas .gitlab/merge_request_templates que contiene el archivo Default.md

Para que se aplique en todas las ramas que tengas abiertas, debes pushear este cambio en la que tengas marcada como rama principal. Eso lo puedes saber en la configuración de tu repositorio.

Si tu rama principal es master y tienes otras ramas previamente abiertas, con que lo pushees a master es suficiente. Cuando crees MR de esas ramas, verás el resultado sin necesidad de haber mergeado el cambio a dicha rama.

Conclusión

De esta forma sencilla conseguimos asegurar que desde el más senior hasta el más junior del equipo jamás olvidan qué cosas deben hacer para completar una tarea, más allá de programar. Nunca más se oirá «terminé la tarea pero olvidé ponerna en pendiente de revisión para que alguien la revisara» o el típico «olvidé testear…».