Tecnología de DevOps: desarrollo basado en troncos

Existen dos patrones principales para que los equipos de desarrolladores trabajen juntos mediante el control de versiones. Uno es usar ramas de funciones, en el que el desarrollador o el grupo de desarrolladores crea una rama, en general, desde el tronco (también conocido como instancia principal o línea principal) y, luego, trabaja de forma aislada en esa rama hasta que se complete la función que compila. Cuando el equipo considera que la función está lista para usarse, vuelve a fusionar la rama de funciones en el tronco.

El segundo patrón se conoce como desarrollo basado en troncos, en el que cada desarrollador divide su propio trabajo en lotes pequeños y combina ese trabajo con el tronco al menos una vez (incluso varias veces) al día. La diferencia clave entre estos enfoques es el permiso. Por lo general, las ramas de funciones involucran a varios desarrolladores y toman días, o incluso semanas, de trabajo. Por el contrario, las ramas en el desarrollo basado en troncos no suelen durar más de unas horas, y muchos desarrolladores combinan los cambios individuales con el tronco de manera frecuente.

En el siguiente diagrama, se muestra un cronograma de desarrollo típico basado en troncos:

Cronogramas de las versiones 1.0 y 1.1, que muestran una corrección de errores de la versión 1.0 combinada con el tronco de la versión 1.1.

En el desarrollo basado en troncos, los desarrolladores envían el código directamente al tronco. Los cambios realizados en las ramas de versión (instantáneas del código cuando está listo para la actualización) se suelen combinar de nuevo en el tronco (representado por las flechas descendentes) lo antes posible. En este enfoque, hay casos en los que las correcciones de errores se deben seleccionar con cuidado y fusionar con las versiones (esto está representado por la flecha hacia arriba), pero estos casos no son tan frecuentes como el desarrollo de funciones nuevas en el tronco. En los casos en que las versiones se actualizan varias veces al día, las ramas de versión no son obligatorias, ya que los cambios se pueden enviar directamente a la instancia principal y se pueden implementar desde allí. Un beneficio clave del enfoque basado en troncos es que reduce la complejidad de combinar eventos y mantiene el código actualizado, ya que tiene menos líneas de desarrollo y realiza combinaciones pequeñas y frecuentes.

En cambio, en el siguiente diagrama, se muestra un estilo de desarrollo típico que no se basa en troncos:

Cronogramas para varias ramas de larga duración, que muestran rutas de combinación complejas y muchos puntos en los que los conflictos de combinaciones pueden ralentizar la actualización del producto.

En este enfoque, los desarrolladores realizan cambios en las ramas de larga duración. Estos cambios requieren eventos de combinación más grandes y complejos en comparación con el desarrollo basado en troncos. Este enfoque también requiere esfuerzos de estabilización adicionales y períodos de “bloqueo del código” o “congelación del código” para garantizar que el software se mantenga en funcionamiento, ya que las combinaciones grandes suelen generar errores o regresiones. Como resultado, debes probar el código después de la combinación y, a menudo, debes corregir los errores.

Cómo implementar el desarrollo basado en troncos

El desarrollo basado en troncos es una práctica necesaria para la integración continua. La integración continua (CI) es la combinación del desarrollo basado en troncos y el mantenimiento de un conjunto de pruebas automatizadas rápidas que se ejecutan después de cada confirmación en el tronco para garantizar que el sistema siempre funcione.

El objetivo de usar la integración continua es quitar las fases de integración y estabilización largas mediante la integración frecuente de pequeños lotes de código. De esta manera, los desarrolladores se aseguran de comunicar lo que hacen, y la integración se deshace de las combinaciones grandes que pueden generar trabajo sustancial para otros desarrolladores y verificadores.

En el paradigma de la CI, los desarrolladores son responsables de mantener el proceso de compilación verde, es decir, en funcionamiento. Esto significa que si el proceso de CI falla, los desarrolladores deben dejar de hacer lo que están haciendo para solucionar el problema de inmediato o revertir el cambio si no se puede solucionar en unos minutos.

La práctica del desarrollo basado en troncos requiere que los desarrolladores sepan cómo dividir su trabajo en lotes pequeños. Este es un cambio significativo para los desarrolladores que no están acostumbrados a trabajar de esta manera.

El análisis de datos de DevOps Research and Assessment (DORA) de 2016 (PDF) y 2017 (PDF) muestra que los equipos alcanzan niveles más altos de entrega de software y rendimiento operativo (velocidad de entrega, estabilidad y disponibilidad) si siguen estas prácticas:

  • Tener tres ramas activas, o menos, en el repositorio de código de la aplicación
  • Combinar las ramas con el tronco al menos una vez al día
  • No tener congelación de código ni fases de integración

Errores comunes

Algunos de los obstáculos comunes para la adopción completa del desarrollo basado en troncos son los siguientes:

  • Un proceso de revisión de código demasiado pesado. Muchas organizaciones tienen un proceso de revisión de código pesado que requiere varias aprobaciones antes de que los cambios se puedan combinar con el tronco. Cuando la revisión del código es complicada y lleva horas o días, los desarrolladores evitan trabajar en lotes pequeños y, en su lugar, agrupan muchos cambios. Esto, a su vez, genera una situación difícil de controlar en la que los revisores se demoran con las revisiones de código debido a su complejidad.

    En consecuencia, las solicitudes de combinación suelen fallar porque los desarrolladores las evitan. Debido a que es difícil calcular el impacto de grandes cambios en un sistema a través de la inspección, es probable que los revisores no reparen en ciertos defectos y no se aprecien los beneficios del desarrollo basado en troncos.

  • Realizar revisiones de código de manera asíncrona. Si el equipo practica la programación en pareja, el código ya lo revisó una segunda persona. Si se requieren más revisiones, se deben realizar de forma síncrona: cuando el desarrollador esté listo para confirmar el código, alguien más debe revisar el código en ese momento. No deben solicitar una revisión asíncrona, por ejemplo, mediante el envío de una solicitud a una herramienta y, luego, el inicio de una tarea nueva mientras esperan la revisión. Cuanto más demore una combinación, más probable es que se generen conflictos de combinación y problemas relacionados. La implementación de revisiones síncronas requiere el acuerdo del equipo para priorizar la revisión del código de los demás sobre otros trabajos.

  • No ejecutar pruebas automatizadas antes de confirmar el código. Para garantizar que el tronco se mantenga en funcionamiento, es esencial que las pruebas se ejecuten con los cambios de código antes de la confirmación. Esto se puede hacer en las estaciones de trabajo para desarrolladores, y muchas herramientas también proporcionan una instalación a fin de ejecutar pruebas de forma remota con los cambios locales y, luego, confirmarlos de forma automática cuando se aprueban. Cuando los desarrolladores saben que pueden colocar el código en el tronco sin demasiado problema, el resultado son pequeños cambios de código fáciles de comprender, revisar, probar y poner en producción más rápido.

Formas de mejorar el desarrollo basado en troncos

En función del debate anterior, estas son algunas prácticas que puedes implementar para mejorar el desarrollo basado en troncos:

  • Desarrolla en lotes pequeños. Uno de los factores más importantes que hacen posible el desarrollo basado en troncos son los equipos que aprenden a desarrollar en lotes pequeños. Esto requiere capacitación y asistencia organizativa para el equipo de desarrollo.
  • Revisa el código de forma síncrona. Como se mencionó antes, pasar a la revisión de código síncrona o, al menos, garantizar que los desarrolladores prioricen la revisión de código ayuda a garantizar que los cambios no tengan que esperar horas, o incluso días, para combinarse en el tronco.
  • Implementa pruebas automatizadas integrales. Asegúrate de tener un conjunto completo y significativo de pruebas de unidades automatizadas y que se ejecuten antes de cada confirmación. Por ejemplo, si usas GitHub, puedes proteger ramas para permitir solo combinaciones de solicitudes de extracción cuando se pasen todas las pruebas. En el instructivo Ejecuta compilaciones con las verificaciones de GitHub, se muestra cómo integrar las verificaciones de GitHub a Cloud Build.
  • Realiza una compilación rápida. El proceso de compilación y prueba debería ejecutarse en unos minutos. Si esto parece difícil de lograr, es probable que haya mejoras que se puedan implementar en la arquitectura del sistema.
  • Crea un grupo principal de capacitadores y mentores. El desarrollo basado en troncos es un cambio importante para muchos desarrolladores, y se puede esperar un poco de resistencia. Muchos desarrolladores no pueden pensar en trabajar de esta manera. Se recomienda buscar desarrolladores que hayan trabajado de esta manera y pedirles que capaciten a otros desarrolladores. También es importante que algunos equipos adopten un estilo de trabajo basado en troncos. Una forma de hacerlo es obtener una cantidad importante de desarrolladores con experiencia en el desarrollo basado en troncos para que al menos un equipo siga las prácticas de este tipo de desarrollo. Luego, puedes hacer que otros equipos adopten este estilo cuando estés seguro de que el equipo que sigue esta práctica tiene el rendimiento esperado.

Formas de medir el desarrollo basado en troncos

Puedes medir la eficacia del desarrollo basado en troncos si sigues estos pasos.

Factor por probar Qué se debe medir Objetivo
Ramas activas en el repositorio de código de la aplicación. Mide cuántas ramas activas tienes en los sistemas de control de versiones de los repositorios de aplicaciones y haz que este número sea visible para todos los equipos. Luego, realiza un seguimiento del progreso incremental hacia el estado del objetivo. Tres o menos ramas activas.
Períodos de congelación de código. Mide cuántas congelaciones de código tiene tu equipo y cuánto duran. Estas mediciones también pueden categorizar cuánto tiempo se invierte en combinar conflictos, en congelaciones de código, en estabilización, etcétera. No se congela el código cuando nadie puede enviar código.
Frecuencia de combinación de ramas y bifurcaciones hacia la instancia principal. Mide un valor binario (sí/no) para cada rama combinada o mide un porcentaje de ramas y bifurcaciones que se combinan todos los días. Se combina al menos una vez al día.
Verifica el tiempo necesario para aprobar los cambios de código. Si realizas una revisión de código de manera asíncrona, mide el tiempo promedio que toma aprobar solicitudes de cambio y presta especial atención a las solicitudes que llevan mucho más que el promedio. Encuentra formas de hacer que la revisión de código se ejecute de forma síncrona y se realice como parte del desarrollo.

Próximos pasos