mobile menu icon

Huyendo de las ramas

Publicado por Rubén Díaz el 25/01/2022

Good Practices, XP, Continuous Integration, TBD, Trunk Based Development


El pasado mes de diciembre, mi compañero Alfredo y yo tuvimos el placer de compartir un par de horas con el equipo de Declarando para hablar sobre feature branching, continuous integration, continuous delivery y algunas técnicas como feature flags y cambio en paralelo.

Hace unos años dimos una charla parecida en la Conferencia Agile Spain, y me gustaría compartir por aquí algunas ideas sobre cómo hacemos integración continua y por qué nos gusta trabajar así.

Gitflow

Cuando empecé mi carrera en el mundo del desarrollo, en todos los proyectos que trabajé me tocó trabajar haciendo Gitflow o variantes similares. Siendo algo tan común en muchas empresas, pensaría que es algo sencillo pero, viendo el flujo de trabajo, la verdad que no lo parece.

Gitflow diagram
From https://nvie.com/posts/a-successful-git-branching-model/

No voy a explicar en profundidad el flujo de trabajo con Gitflow, pero sí que hay un detalle que salió cuando tuvimos la charla con el equipo de Declarando y que me resultó muy llamativo.

La rama master (o main como solemos llamarla hoy en día) es la que se despliega a producción, y vemos que hay 2 formas de llegar a master: mediante una rama de hotfix o mediante una rama de release. Viendo sólo la figura de arriba, se ve que introducir código a master desde un hotfix es más “rápido” (hay menos ceremonias de commits y ramas) que entrar a través de release. La gente de Declarando nos decía “es que a veces la gente de producto viene con una historia de usuario y nos la quiere colar como un hotfix”. Eso también me ha pasado a mi en algún trabajo pero veámoslo desde la perspectiva de alguien de producto que no tiene porqué entender Gitflow. Yo quiero una feature, hay una forma “lenta” de tenerla en producción y una forma “rápida”. ¿Cuál quiero yo? Pues la rápida, obviamente.

Aparte de la anécdota, ¿tiene sentido tener dos formas de llegar a producción?[1] ¿Por qué aceptamos tener una forma lenta de desplegar si podemos hacerlo de forma más rápida? ¿O es que elegimos hacer un despliegue de forma menos segura para arreglar un problema en producción?

Incertidumbre e inventario

Has estado una semana trabajando tranquilamente en tu rama y anuncias en la daily que la feature está terminada, pero es mentira porque has dejado para el final la integración de tu rama con la rama principal del proyecto. En ocasiones tendrás suerte y será fácil, y otras veces te tocará resolver un conflicto que te llevará media mañana. Además, como resolver el conflicto te ha parecido molesto la próxima vez intentarás tocar el mínimo código posible para evitar conflictos. A partir de ese momento habrás perdido el refactor oportunista[2], aquel que hacemos a modo de scout dejando el código por el que pasamos mejor de lo que estaba, ya que ahora no quieres modificar el código por miedo a tener que resolver conflictos.

En términos de Lean, podemos entender el trabajar en una rama como una optimización local (trabajar en una rama sin que nos molesten es más cómodo que traer cambios de todo el equipo a menudo), pero desde el punto de vista global no es la forma más óptima porque retrasamos el aprendizaje de integrar. Además, el código que está en una rama es inventario, stock que hemos producido y dejado sin entregar, retrasando el valor.

Feedback y pull requests

¿Y cómo se suelen llevar los cambios de una rama a main? Normalmente a través de pull requests que bloquean el merge de la rama hasta que X personas lo aprueban. Los pull requests pueden ser una herramienta muy chula para compartir conocimiento y debatir cómo se desarrolla una solución en equipos que cumplen alguna de estas condiciones:

En una empresa en la que el equipo no está distribuido (o está distribuido pero en zonas horarias cercanas) los pull requests son una manera de revisar código mucho más compleja que hacer pairing o mostrar los cambios al resto del equipo en una mini reunión. ¿Por qué? Imaginemos un equipo de 4 personas, donde cada persona empieza una tarea en una rama. Cuando la primera persona acaba su tarea, hace una pull request y pide al resto de compañeras que revise para poder hacer merge. El resto del equipo está ocupado, así que empezamos una tarea nueva mientras esperamos su feedback. Una de las personas se libera y empieza a revisar el código, pero resulta que el pull request tiene 100 cambios, así que lo mira en diagonal y le da el ok. Al día siguiente, otro miembro del equipo revisa la pull request con más detenimiento y anota 10 comentarios. El desarrollador que hizo la tarea inicialmente recibe una notificación con los comentarios, deja de trabajar en la tarea con la que estaba y lee los comentarios intentando recordar por qué hizo las cosas de esa manera. Así hasta que todo el equipo lo ve ok y se hace merge del pull request. Y mientras tanto la gente de producto esperando que nos pongamos de acuerdo en cómo llamar a una variable en una tarea supuestamente “terminada”.

¿Qué problemas vemos aquí?

Mejora contínua, conoce tu contexto

Con este post no quiero que te vayas con la idea de “tengo que hacer trunk based development”. Es importante siempre conocer la teoría, practicar las técnicas en cosas que tengan poco riesgo (de esto hablaremos en otros posts) y, si encaja en tu contexto, dar el salto. Al final lo importante es cuestionar siempre lo que hacemos. No decir “es que en la empresa siempre hemos hecho gitflow”, sino pararte a pensar, detectar posibles problemas y encontrar cosas que podrías ir probando para mejorar.

Por último, te dejo algunas acciones que puedes intentar aplicar para ir reduciendo algunos de los problemas de Gitflow.

Notas

[1] Al respecto de tener dos formas de desplegar en producción, Charity Majors publica un tweet diciendo que solo debería haber una forma de desplegar, y no tener una forma corta “insegura” para usar justo en los momentos de estrés.

[2] En la charla Workflows of refactoring Martin Fowler explica el concepto de refactoring oportunista.

[3] Otro post relacionado con el concepto de Consensus-Driven Development de Nicholas C. Zakas

Volver a posts