Llevar adelante la integración de las distintas partes sobre la que se va desarrollando un proyecto de software puede resultar complicado: si son varios subequipos dentro del equipo de desarrollo, llegar a una versión estable del proyecto, con todas las mejoras implementadas, puede requerir de mucho esfuerzo, retrabajo y tiempo de atención.
En este artículo, veremos qué es la integración continua y cómo ayuda a resolver los puntos de dolor que puede conllevar llegar a un producto estable de un proyecto de desarrollo.
La integración continua es una práctica donde cada equipo de desarrollo dentro de un proyecto común integra su trabajo varias veces al día. Cada integración es llevada a cabo junto a una herramienta de buildeo automático, que puede correr tests que chequeen rápidamente posibles errores resultantes de la suma de las nuevas funcionalidades al proyecto.
¿Cómo se lleva adelante la práctica?
Supongamos que estamos en un equipo de desarrollo y realizando cambios sobre un proyecto compartido con otros equipos en un repositorio remoto (a través de algún VCS, como Git), que también lo mantienen y agregan nuevas funcionalidades. Por ahora, la regla del negocio del proyecto no influye.
Queremos incorporar una nueva funcionalidad al proyecto. Para ello, nos bajamos a nuestro entorno de trabajo local (nuestras computadoras) una copia de la rama principal del proyecto. Realizamos un buildeo y luego ejecutamos los test para corroborar que es estable lo que se encontraba en la rama principal.
Comenzamos a trabajar sobre la nueva funcionalidad. Una vez desarrollado el primer avance, volvemos a buildear el proyecto y a correr los test. Por las dudas de que algún otro miembro haya realizado algún cambio en la rama principal, volvemos a traernos los cambios a nuestro entorno local antes de realizar un commit a la rama principal del repositorio remoto, volvemos a builder y correr tests. Si alguna falla sucede durante el proceso de buildeo, nos dedicamos a corregir los errores que suceden.
Luego, volvemos a realizar un build y correr los test. Una vez que se han integrado los cambios de la rama principal con los que la copia local, podemos realizar el commit al repositorio remoto.
Aunque realizado el commit no finaliza el proceso. Una vez realizado, se realiza el mismo proceso de buildeo y testing (manual o automático) sobre la rama principal actualizada, pero esta vez en un servidor de integración. Si algún error ocurre durante este proceso, se realiza la corrección lo más rápido posible, dado que el funcionamiento del código se va diluyendo pasado el tiempo. Más allá de las buenas prácticas de desarrollo, uno tiene más fresco el código como para encontrar dónde pueden estar pasando los errores. Sean debidos a nuestro trabajo o el de otro equipo, la corrección se realiza rápido.
En esta etapa de la práctica, puede sumarse el envío de un correo a los desarrolladores o de un reporte de cómo sucedió la integración en la rama principal.
De este modo, se genera un código más estable y con menos errores. El equipo puede tener varias integraciones al día, pero recibe un rápido feedback de las nuevas implementaciones.
Antes de la integración continua...
En un esquema más tradicional de desarrollo, los desarrolladores trabajan aislados con un agregado a un proyecto, y hasta que el desarrollo no estuviera terminado, no se realizaba la integración. Una vez finalizado, el equipo de desarrollo delegaba el trabajo de integrar los cambios a la rama estable del proyecto al equipo de integración y buildeo, que se encargaba de integrar los nuevos cambios al proyecto principal, luego realizar la compilación y el buildeo a entregar al equipo de operaciones, quienes tenían la tarea de realizar el despliegue de la aplicación para certificación o producción.
Dada la magnitud de los cambios, el proceso podía durar varias horas por cambio a integrar, lo que alentaba la entrega del ejecutable. Si un error ocurría en el proceso, el equipo de integración contactaba a cada equipo de desarrollo encargado para resolverlo. Dado que los equipos no tenían tan fresco el código por el paso del tiempo entre el pasaje del nuevo cambio a su integración, era más difícil encontrar la razón del error y por consecuencia sumaba más tiempo a disponer del ejecutable a entregar. Si los equipos estaban trabajando en nuevos desarrollos, esta reunión con el equipo de integración les suponía cortar el trabajo para sumarse a resolver los errores.
¿Qué beneficios trajo la integración continua?
Problemas rápidamente detectados debido a una integración frecuente
Dado que la integración continua supone varios procesos de integración y buildeo al día de las nuevas funcionalidades, cada pequeño cambio realizado por el equipo puede generar errores, pero son rápidamente detectados por los responsables del cambio del código.
La integración es automática y rápida
Ya que el proceso de integrar cambios ahora es delegado a cada parte del equipo de desarrollo, sumar las nuevas funcionalidades a la rama principal de trabajo (donde está la versión estable del proyecto) es automática: de realizarse de otra manera (por ejemplo, integrando recién al finalizar todas mejoras planificadas), requeriría mucho tiempo y esfuerzo, integrar cambio por cambio esperando la consistencia del proyecto, y dado el paso del tiempo los cambios no se encuentran tan frescos en los desarrolladores en caso de ocurrir fallas de integración.
La tarea de corregir errores es delegada a los desarrolladores
En un esquema diferente de integración, ésta podía estar a cargo de un equipo diferente, que luego contactaría a cada parte del equipo de desarrollo según vaya las mejoras sobre las cuales hayan trabajado, y la corrección de errores quedaría a cargo de este equipo. En Integración Continua, la corrección de errores queda a cargo de los desarrolladores que realizaron las nuevas funcionalidades, que tienen una rápida respuesta de la consistencia de los cambios con la versión estable del proyecto en la rama principal
Ciclo de feedback más corto
Como sumar cada pequeño cambio a la versión estable del proyecto queda a cargo de los desarrolladores, ahora éstos cuentan con un más rápido feedback del funcionamiento del código: de funcionar bien, continúan realizando el desarrollo de nuevas funcionalidades; de lanzar errores, es trabajo de ellos corregirlos e integrar los cambios una vez corregidos los errores.
Más rápidos releases
Como hay ciclos de desarrollo más cortos (cada nueva funcionalidad es integrada por cada equipo), puede enviarse a QA o a producción la aplicación en sus versiones con las pequeñas funcionalidades.
Desventajas...
Más allá de los beneficios que tiene la aplicación de la Integración Continua, llevarla adelante implica ciertas condiciones y genera consecuencias de esfuerzo, entre ellas:
Más responsabilidades al equipo de desarrollo
Al no haber un equipo dedicado a la integración de cada nueva funcionalidad agregada y realizarlo los desarrolladores como parte de su trabajo diario: se suma al desarrollo en sí la cultura de integrar el código frecuentemente y testearlo.
Entorno adicional de integración
Para realizar la integración a la base estable del proyecto y correr los tests, es necesario contar con una réplica lo más parecida al servidor productivo.
Podemos ver que el objetivo principal de incorporar la práctica de Integración Continua es el de, ante cada nueva funcionalidad agregada, generar una versión estable del proyecto, con un buen grupo de tests que verifiquen su correcto funcionamiento, y que sea menos propenso a cometer errores, de modo de tener un producto más fácilmente ofrecido a nuestros usuarios finales. Incorporarlo puede suponer varios factores, como el mantenimiento de un repositorio remoto compartido, el hábito de hacer varias integraciones al día, la incorporación de un servidor de integración, pero tiene su gran ganancia de mantener un código estable menos propenso a errores y más fácilmente entregable.