Desarrollo basado en troncos

Descubre por qué esta práctica de gestión de control de versiones es habitual entre los equipos que siguen la metodología DevOps.

Kev Zettler Kev Zettler

Resumen: el desarrollo por tronco es una práctica de gestión de control de versiones en la que los desarrolladores fusionan pequeñas actualizaciones de forma frecuente en un "tronco" o rama principal. Dado que esta práctica simplifica las fases de fusión e integración, ayuda a lograr la CI y la CD y, al mismo tiempo, aumenta la entrega de software y el rendimiento de la organización.

En los primeros tiempos del desarrollo de software, los programadores no disfrutaban del lujo de los sistemas de control de versiones modernos. Más bien, desarrollaban dos versiones del software a la vez para poder realizar un seguimiento de los cambios y revertirlos si era necesario. Con el tiempo, este proceso resultó ser muy laborioso, costoso e ineficiente.

A medida que los sistemas de control de versiones se desarrollaron, surgieron varios estilos de desarrollo que permitieron a los programadores encontrar errores con más facilidad, crear código en paralelo con sus compañeros y acelerar el ritmo de publicación. Hoy en día, la mayoría de los programadores aprovechan uno de estos dos modelos de desarrollo para ofrecer software de calidad: Gitflow y desarrollo basado en troncos.

Gitflow, que se popularizó primero, es un modelo de desarrollo más estricto en el que solo determinadas personas pueden aprobar los cambios en el código principal. Así se mantiene la calidad del código y se minimiza el número de errores. El desarrollo basado en troncos es un modelo más abierto, ya que todos los desarrolladores tienen acceso al código principal, lo que permite a los equipos iterar con rapidez y pone en práctica la CI y la CD.

¿Qué es el desarrollo basado en troncos?

El desarrollo basado en troncos es una práctica de gestión de control de versiones en la que los desarrolladores fusionan pequeñas actualizaciones de forma frecuente en un "tronco" o rama principal. Se ha convertido en una práctica habitual entre los equipos de DevOps y parte del ciclo de vida de DevOps, ya que simplifica las fases de fusión e integración. De hecho, el desarrollo basado en troncos es una práctica obligatoria de la CI y la CD. Permite a los desarrolladores crear ramas de corta duración con pequeñas confirmaciones, a diferencia de otras estrategias de ramas de funciones de larga duración. A medida que la complejidad del código base y el tamaño del equipo van creciendo, el desarrollo basado en troncos ayuda a mantener el flujo de publicación de la producción.

Comparación de Gitflow y desarrollo basado en troncos

Gitflow es un modelo alternativo de creación de ramas en Git que utiliza ramas de función de larga duración y varias ramas principales. Gitflow tiene más ramas de mayor duración y confirmaciones más grandes que el desarrollo basado en troncos. Según este modelo, los desarrolladores crean una rama de función y retrasan su fusión con la rama principal del tronco hasta que la función esté completa. Estas ramas de funciones de larga duración requieren más colaboración para fusionarlas, ya que presentan un mayor riesgo de desviarse de la rama troncal e introducir actualizaciones conflictivas.

Gitflow también tiene líneas de rama principales independientes para el desarrollo, las correcciones, las funciones y las publicaciones. Existen diferentes estrategias para fusionar las confirmaciones entre estas ramas. Al haber más ramas que gestionar y compaginar, suele haber más complejidad, por lo que se requieren sesiones adicionales de planificación y revisión por parte del equipo.

El desarrollo por tronco está mucho más simplificado, ya que se centra en la rama principal como fuente de correcciones y publicaciones. En este tipo de desarrollo, se da por sentado que la rama principal permanece estable, sin incidencias, y siempre está lista para la implementación.

Ventajas del desarrollo basado en troncos

El desarrollo basado en troncos es una práctica obligatoria para la integración continua. Si los procesos de desarrollo y prueba están automatizados, pero los desarrolladores trabajan en ramas de funciones aisladas y largas que se integran con poca frecuencia en una rama compartida, la integración continua no está a la altura de su potencial.

El desarrollo basado en troncos disminuye la fricción de la integración del código. Cuando los desarrolladores terminan una tarea nueva, deben fusionar el código nuevo en la rama principal; pero no deben fusionar los cambios en el tronco hasta que hayan comprobado que los pueden compilar correctamente. Durante esta fase, pueden surgir conflictos si se han realizado modificaciones desde el inicio de la tarea nueva. En concreto, estos conflictos son cada vez más complejos a medida que los equipos de desarrollo crecen y la base de código se amplía. Esto ocurre cuando los desarrolladores crean ramas independientes que se desvían de la rama origen y otros desarrolladores están fusionando a la vez el código que se solapa. Por suerte, el modelo de desarrollo basado en troncos reduce estos conflictos.

Permite la integración continua del código

En el modelo de desarrollo por tronco hay un repositorio con un flujo constante de confirmaciones que se incorporan a la rama principal. El hecho de añadir un conjunto de pruebas automatizadas y la supervisión de la cobertura de código a este flujo de confirmaciones contribuye a una integración continua. Cuando se fusiona un código nuevo en el tronco, se ejecutan pruebas automatizadas de integración y cobertura de código para validar la calidad de dicho código.

Garantiza la revisión continua del código

Las rápidas y pequeñas confirmaciones del desarrollo basado en troncos convierten la revisión del código en un proceso más eficiente. Gracias a las ramas pequeñas, los desarrolladores podrán ver y revisar con rapidez los pequeños cambios. Esto resulta mucho más fácil en comparación con una rama de función de larga duración en la que un revisor lee páginas de código o inspecciona de forma manual una gran superficie de cambios de código.

Permite la publicación consecutiva de código en producción

Los equipos deben hacer fusiones a diario y con frecuencia en la rama principal. El objetivo del desarrollo por tronco es que la rama del tronco siempre tenga luz verde, de modo que siempre esté lista para la implementación con cualquier confirmación. Las pruebas automatizadas, la cobertura de código y las revisiones de código proporcionan un proyecto de desarrollo por tronco con la garantía de estar listo para hacer la implementación en producción en cualquier momento. De este modo, el equipo puede hacer implementaciones en producción con frecuencia y agilidad y fijar más objetivos para la publicación de producción diaria.

Desarrollo basado en troncos y CI o CD

A medida que la CI y la CD ganaban popularidad, los modelos de creación de ramas se fueron perfeccionando y optimizando, lo que derivó en el aumento del desarrollo basado en troncos. Ahora, dicho desarrollo constituye un requisito de la integración continua. Gracias a esta integración, los desarrolladores pueden aplicar el desarrollo basado en troncos y efectuar pruebas automatizadas que se ejecutan cada vez que se llevan a cabo confirmaciones en uno de ellos, lo que garantiza que el proyecto funcione en todo momento.

Prácticas recomendadas en el desarrollo basado en troncos

El desarrollo basado en troncos garantiza que los equipos publiquen el código de forma rápida y coherente. A continuación, se presenta una lista de ejercicios y prácticas que te ayudarán a perfeccionar el ritmo de trabajo de tu equipo y a desarrollar un calendario de publicaciones optimizado.

Desarrollar en lotes pequeños

El desarrollo basado en troncos sigue un ritmo rápido para enviar el código a producción. Si dicho desarrollo fuera como la música, se trataría de un staccato rápido: notas cortas y sucintas en rápida sucesión (si entendemos que las confirmaciones del repositorio son las notas). Al mantener un número pequeño de confirmaciones y ramas, se podrán realizar fusiones e implementaciones con más rapidez.

Los pequeños cambios de un par de confirmaciones o la modificación de unas pocas líneas de código minimizan la sobrecarga cognitiva. Resulta mucho más fácil para los equipos mantener conversaciones significativas y tomar decisiones rápidas cuando se revisa un área limitada de código en lugar de un conjunto extenso de cambios.

Marcas de función

Las marcas de función complementan perfectamente el desarrollo por tronco, ya que permiten a los desarrolladores empaquetar nuevos cambios en una ruta de código inactiva y activarla más adelante. Así, los desarrolladores pueden renunciar a crear una rama de función independiente en el repositorio y centrarse en confirmar código nuevo de función directamente en la rama principal, dentro de una ruta de marca de función.

Las marcas de función fomentan de manera directa las actualizaciones de lotes pequeños. En lugar de crear una rama de función y esperar a desarrollar la especificación completa, los desarrolladores pueden crear una confirmación en el tronco que introduce la marca de función y envía nuevas confirmaciones en el tronco que generan la especificación de la función dentro de la marca.

Implementar pruebas automatizadas exhaustivas

Las pruebas automatizadas son necesarias para cualquier proyecto de software moderno que pretenda alcanzar la CI y la CD. Hay varios tipos de pruebas automatizadas que se ejecutan en diferentes etapas del proceso de publicación. Las pruebas unitarias y de integración de corta duración se ejecutan durante el desarrollo y al fusionar el código. Las pruebas de extremo a extremo, de pila completa y de larga duración se ejecutan en fases posteriores del proceso en un entorno completo de ensayo o producción.

Las pruebas automatizadas facilitan el desarrollo basado en troncos al mantener un ritmo de lotes pequeños a medida que los desarrolladores fusionan confirmaciones nuevas. La serie de pruebas automatizadas revisa el código para detectar cualquier incidencia y lo aprueba o rechaza automáticamente. Esto ayuda a los desarrolladores a crear rápidamente confirmaciones y ejecutarlas a través de pruebas automatizadas para ver si introducen incidencias nuevas.

Realizar revisiones de código asíncronas

En el desarrollo basado en troncos, el código no se puede colocar en un sistema asíncrono para revisarlo más tarde; hay que revisarlo de inmediato. Las pruebas automatizadas proporcionan una capa de revisión de código preventiva. Cuando los desarrolladores están listos para revisar la solicitud de incorporación de cambios de un miembro del equipo, en primer lugar, pueden comprobar que las pruebas automatizadas se han superado y que la cobertura del código ha aumentado, lo que da al revisor la seguridad inmediata de que el código nuevo cumple especificaciones determinadas y se podrá centrar en optimizarlo.

Tener tres o menos ramas activas en el repositorio de código de la aplicación

Una vez que una rama se fusiona, se recomienda eliminarla. Un repositorio con una gran cantidad de ramas activas provoca una serie de efectos colaterales un tanto inoportunos. Aunque el hecho de poder ver qué tarea está en curso analizando las ramas activas resulta ventajoso para los equipos, dicha ventaja se pierde si hay ramas inactivas y obsoletas. Algunos desarrolladores utilizan interfaces de usuario de Git que pueden llegar a ser difíciles de manejar al cargar un gran número de ramas remotas.

Fusionar las ramas con el tronco al menos una vez al día

Los equipos de desarrollo por tronco de alto rendimiento deben cerrar y fusionar al menos una vez al día cualquier rama que haya abierta y lista para fusionar. Este ejercicio ayuda a mantener el ritmo y marca una cadencia para la supervisión de las publicaciones. Los equipos pueden etiquetar el tronco principal al final del día como confirmación de publicación, lo cual contribuye a crear un incremento ágil diario.

Reducir el número de bloqueos de código y fases de integración

Los equipos que siguen la metodología ágil y aplican las técnica de CI y CD no deberían tener que planificar bloqueos o pausas del código para las fases de integración, aunque una organización puede requerirlo por otros motivos. El adjetivo “continua” en CI y CD implica que las actualizaciones fluyen constantemente. Los equipos de desarrollo basado en troncos deben tratar de evitar el bloqueo del código y planificar en consecuencia para garantizar que el proceso de publicación no se estanque.

Compilar rápido y ejecutar de inmediato

Para mantener un ritmo rápido de publicaciones, hay que optimizar los tiempos de compilación y ejecución de pruebas. Las herramientas de compilación de CI y CD deberían utilizar capas de almacenamiento en caché cuando sea apropiado para evitar procesados costosos del contenido estático. Las pruebas se deben optimizar para utilizar los códigos auxiliares (stubs) adecuados para los servicios de terceros.

En conclusión...

El desarrollo basado en troncos es actualmente el estándar para los equipos de ingeniería de alto rendimiento, ya que establece y mantiene un ritmo de publicación de software mediante el uso de una estrategia de creación de ramas Git simplificada. Además, el desarrollo basado en troncos ofrece a los equipos de ingeniería más flexibilidad y control sobre la forma de lanzar el software para el usuario final.