Estrategias de integración

10:15 0 Comments

En anteriores ocasiones hemos hablado del futuro de la integración continua, teniendo en cuenta tanto del libre de Duvall como otras posibles alternativas.

Hoy me voy a centrar precisamente en este tema: diferentes alternativas para gestionar la fase de integración.

Algunos preferirán seguir con el estilo de desarrollo en la línea principal mientras que otros optarán por una integración más controlada (y posiblemente menos ágil).

Además de la estrategia de manejo de ramas seleccionada habrá que tener una estrategia de integración.
Comencemos con el desarrollo de la línea principal. Esta es, probablemente, la técnica más conocida y extendida en control de versiones. ¿Cómo funciona? Sencillo, todas las protecciones van a la rama principal, como se puede observar en la siguiente figura:


Por supuesto que tiene sus propias ventajas y desventajas.

Ventajas de la línea principal
  • Es simple de configurar y fácil de usar
  • Cualquier sistema de control de versiones es capaz de manejar esta estrategia (al menos todos soportan el trabajo en la línea principal)

    Desventajas de la línea principal
  • Puede llevar a la inestabilidad del proyecto.
  • Los usuarios tienen la última versión después de cada commit, así que se pueden ver fácilmente infectados por un "error en movimiento".
  • Para prevenir los problemas anteriores los desarrolladores deben de hacer commit de sus cambios sólo cuando hayan comprobado el código. Esto puede llevar a que el código esté fuera del control de versiones mucho tiempo. Además los desarrolladores comienzan a utilizar el control de versiones como su único mecanismo de entrega, ya no es una herramienta para desarrollar, no pueden proteger sus cambios cada cinco minutos a no ser que estén totalmente seguros de que los nuevos cambios no romperán la estabilidad de la versión...Entonces se pierde la capacidad de utilizar el control de versiones para saber por qué el código estaba funcionando antes de un pequeño cambio que se hizo...



  • Las prácticas estándar de Integración Continua intentan resolver todos los problemas en base a dos principios:

  • Hacer commit con la mayor frecuencia posible, incluso varias veces al día, (por favor tener en cuenta: varias veces al día es menos de lo que protegerías tu código si tuvieses una rama en la que incluir incluso el código en el que no están trabajando en ese momento, simplemente para ayudarte en tu desarrollo).
  • Hay que asegurarse siempre de no romper la versión estable. Será necesario el utilizar un potente conjunto de tests para comprobar los cambios junto con los anteriores. Si se sigue un desarrollo basado en testing entonces se puede lograr este objetivo de manera más fácil.
  • Lo que obtienes por contrapartida es un proyecto que evoluciona de manera muy rápida, lo cual es genial. El problema que generalmente encuentro es que los equipos tienen dificultades por estar previniendo que no se destruya lo ya creado, y normalmente prefieren cambiar evolución por estabilidad. Por supuesto esto no es siempre así.

    Algunas alternativas
    La alternativa de la que voy a hablar es el patrón de rama por tarea. Algunos de sus aliados son: Ramificación activa, ramificación por tareas, ramificación lateral o ramificación transitoria. Es probablemente mi patrón favorito por su flexibilidad, facilidad de uso y sus beneficios asociados. Además sienta las bases de nuevas tendencias en control de versiones tales como la gestión de streams.

    ¿Qué aspecto tiene el patrón de rama por tarea? Mira la siguiente figura:

    Está la línea principal, que se ha etiquetado como “BL00” y hay una rama para una tarea denomiada task001.
    Aquí hay tres importantes asuntos a tener en cuenta:
  • Cada tarea comienza desde una línea base conocida: se elimina el problema de errores que siguen apareciendo.
  • La línea base no sólo recibirá los cambios estables. Se refuerza el principio de "nunca corromper la línea principal”.
  • Se crea un enlace explícito entre las tareas creadas en el sistema de gestión de tareas (como Jira, DevTrack, VersionOne, OnTime, Mantis, Bugzilla o un mecanismo interno). Aquí hay algo realmente importante: un desarrollador trabaja en una rama que sabe que está enlazada a una tarea, ya que tiene el nombre de esa tarea!. Así que los desarrolladores saben exactamente en que ítem están trabajando. Esto quiere decir que tanto los responsables de proyecto como los desarrolladores por fin hablan el mismo idioma!

    Aquí desaparecen todos los problemas del trabajo en la línea principal. El punto negativo es que es un poco más complicado de entender (sólo un poco...) y no lo soportan todos los controles de versiones (por eso hemos desarrollado Plastic!).

    Rápidamente estarás creando más ramas para implementar más cambios, como se puede ver en la siguiente imágen:



    Pero la cuestión no es sólo cómo y cuándo crear tus ramas, sino cómo, cuándo y quién las va a volver a integrar en la línea principal.

  • Abordaré este tema desde dos enfoques diferentes.

    Ejecutar mini-bigbangs
    Has decidido usar rama por tarea y tus colegas llevan varios días creando ramas. ¿Cuándo deberías integrarlas dentro de la línea principal?

    Yo, normalmente, te diría: no esperes más de una semana. De hecho si dejas que transcurra más de una semana entre integraciones seguramente te encuentres con uno de los mayores problemas del control de versiones: la integración big-bag.


    La integración big bang integration es un problema muy conocido y documentado, una de las “raíces de la maldad” en desarrollo de software, pero ahí sigue esperando nuevas víctimas.

    ¿Cómo funciona? Digamos que estás trabajando en un proyecto de 6 meses. Entonces planeas 2 fases y divides el equipo de subequipos. Trabajan en características diferentes e integrarán su trabajo una semana antes de cada fase. ¿Suena familiar? Bien, espero que no ya que es una receta estupenda para el desastre!

    Si sigues este enfoque en lugar de una semana, probablemente tu primera “integración” tardará mucho más, y no es necesario decir que la segunda no será mejor… Obtendrás una gran cantidad de software que nunca antes se había integrado y necesitarás estar seguro de que funciona… en una semana! Una locura.

    Esto responde al porqué es una buena idea reducir el tiempo entre integraciones. Yo diría que la frecuencia de integración tiene que ser inversamente proporcional a la cantidad de trabajo que tu equipo pueda realizar. Me explico, si estás trabajando en un pequeño grupo de 5 desarrolladores, puede que te vaya bien ejecutando una integración a la semana, pero tan pronto como vayas creciendo, tal vez tengas que integrar con más frecuencia, incluso más de una vez al día.


    Lo que se intenta evitar son los problemas de integración. Es exactamente la misma regla que introduce la integración continua: si algo puede dar errores...¡hacerlo con la mayor frecuencia posible para reducir el riesgo!

    Y recuerda que el problema de la integración no debería ser el integrar ficheros y directorios, si esto es así: ¡cambia a otro control de versiones! El problema es, que incluso cuando el código se compila correctamente, puede destruir muchos tests o esconder un inesperado número de errores críticos. Como he mencionado, el problema no debería ser la integración. Estuvimos trabajando con una empresa que ejecutaba integraciones semanales con CVS. . Ellos necesitaban muchas horas para integrar el código. Entonces cambiaron a Plastic y emplean el tiempo que ahorraron en ejecutar un test suite completo. Esta es la fortaleza de la integración, el estar seguro de que tu código funciona como se espera, y no estando preocupado de cómo integrarlo.


    Habiendo dicho esto veamos una pequeña iteración de integración:



    Yo las llamo “mini-bigbangs” porque en realidad son integraciones big bang: coges un número de cambios separados del código desarrollado y los integras. La clave es que son tan pequeños que el germen del “big-bang” no se muestra.

    ¿Entonces por qué ejecutamos aún este enfoque, por qué no vamos directamente a la pura integración continua en la línea principal? Bien, el tener tu propia rama para cada tarea es una gran idea, te permite tener un espacio para hacer cambios y previene que la línea principal se corrompa, aparte de todas las demás ventajas del modelo rama por tarea.

    Entonces continúas trabajando y tu desarrollo tendrá el aspecto de la siguiente figura:



    Hasta que realizas otra integración y:


    ¿Está ahora más claro? Recuerda que los tests son la piedra angular de este enfoque de integración. Debes verificar que se cumple un subset del test completo para ser ejecutado y terminar así la tarea (puedes instalar un servidor para hacerlo, buscando nuevas tareas acabadas, descargando, compilando y comprobándolas unitariamente una vez que están marcadas y terminadas).

    Existen algunas advertencias a tener en cuenta: he estado ejecutando este tipo de integración con gran éxito en diferentes proyectos, pero puede pasar que, por alguna razón, la integración llegue a ser un auténtico infierno. En mi caso ocurrió, fue a causa de los tests: se hicieron tan grandes que la comprobación de cada tarea en la integración (es algo que se tiene que hacer!) era demasiado costosa. Entonces la integración empezó a crecer más y más, y se convirtió en un auténtico dolor, como dije antes.


    Por rfavor ten en cuenta que el verdadero problema no está en el campo del control de versiones sino en el del test: puede que los test sean frágiles o que te lleven mucho tiempo, y se tienen que fijar de alguna manera. Intentemos buscar algunas alternativas.

    La primera se puede conocer como integración escalonada: el desarrollador, ejecutando el “mini big-bang”, decide agrupar las tareas juntas, integrarlas en diferentes ramas de integración intermedias, testarlas en paralelo e integrarlas todas juntas en la rama principal.



    Recuerda que aquí la clave está en no apresurarse demasiado con la integración, la cual es ya muy rápida de por si, pero hay que ser capaz de ejecutar el mayor número posible de test en paralelo mientras se integran las ramas.

    Integración rama por tarea e integración continua
    Si estuvieras en la situación de tener una enorme batería de tests y necesitaras impedir cualquier retraso en las integraciones, o quisieras evitar el papel del integrador (en el enfoque más ágil) o buscar un ciclo de trabajo más rápido, podrías combinar la técnica de rama por tarea con el enfoque de integración continua.



    Con este enfoque cada desarrollador integra su propia rama en la línea principal. Recordemos que primero debe (como se muestra en la segunda rama) integrar hacia abajo, desde la rama principal, para coger los últimos cambios, después se deben ejecutar los test (usando un servidor de integración contínua, por ejemplo) y sólo cuando estos se hayan pasado, integrar los cambios en la principal (será sólo un “copiar integración”).

    Entonces se lanzará una versión en la rama principal, incluso una larga, y todo va bien, con lo que se crea una nueva versión del software.



    Integración continua con ramas de versiones

    Hay más opciones. Supongamos que cada desarrollador integra sus cambios en una "rama de integración" como muestra la siguiente figura:



    La rama de versión se puede utilizar para realizar integraciones durante el día y luego por la noche dejar funcionando un proceso de testing automatizado. Si todo funciona como debería la rama de la integración con los cambios realizados durante el último día se puede integrar automáticamente en la rama principal, se crea una nueva versión y se utiliza como línea base de desarrollo durante el siguiente día.



    En resumen
    Como podéis ver hay varias alternativas al realizar integraciones, desde las más simples a las más sofisticadas. Yo siempre sigo el principio de hacer las cosas del modo más sencillo posible. Por supuesto que esta no es siempre la mejor opción así que hay que ver cual es la mejor alternativa para cada equipo.

    ¿Quieres intentarlo tú mismo
    Si quieres intentarlo puedes descargar Plastic desde este enlace? También disponible en versión Linux.

    0 comentarios: