Buenas prácticas: la integración continua

En el último artículo, hablaba de la necesidad de las pruebas, para el aseguramiento de la entrega de valor. Y ciertamente, en uno de los comentarios acertaron plenamente a nombrar otra práctica, muy necesaria para la entrega de valor. La integración continua.

Seguro que muchos habéis vivido esta situación, dos, tres días antes de pasar a un entorno, desarrollo o preproducción (en el mejor de los casos), o incluso a producción (en el peor de los casos), alguien va al control de código fuente y obtiene la última versión, todos sabemos que esto debería hacerse a diario, pero eso es tema de otro artículo. El caso es que se trae todo, y lanza la compilación, y lo siguiente que se oye es “ups, no compila”, la cara se nos desencaja, a todo el equipo, y pensamos ¿qué ha pasado? Y ahora ¿qué binarios desplegamos?

Otra situación que puede ocurrir, igual de preocupante, una vez con la última versión, lo compilamos en “cualquier máquina”, todo va bien, lo subimos al entorno, y de repente algunas funcionalidades, dependientes de referencias externas fallan, y oímos la frase “en mi máquina (la de compilación) funciona”. Esto habitualmente es debido a que no hemos usado una máquina limpia (con las referencias en la misma versión que tendremos en los entornos), para esa compilación. Son situaciones, que por desgracia, veo más frecuentemente de lo que me gustarían.

¿Qué método tenemos para evitar o minimizar esto? La integración continua.
Esta práctica consiste en tener un proceso automatizado que, después de que cada desarrollador suba código al repositorio, se obtenga la última versión, se compile, se ejecuten el conjunto de pruebas unitarias seleccionado, y se dejen los binarios/resultados en una ubicación conocida.

Las ventajas de esto son claras, la primera, cada vez que alguien sube algo al control de código fuente, tenemos un proceso que verifica que al menos la integración, y las pruebas unitarias se ejecutan y sabemos el resultado. Importante es que, en un equipo, si se rompe la integración continua, por el motivo que sea, la prioridad es solucionar el problema, os aseguro que por sí sólo no se va a solucionar, y por supuesto, independientemente de quién sea el código que ha roto la integración, todo el equipo debe colaborar para arreglarlo.

Otra gran ventaja, orientada a la entrega de valor, es que sin un esfuerzo adicional, en cualquier momento del sprint o iteración, podemos disponer de un conjunto de binarios, compilados con la última versión, y con su conjunto de pruebas unitarias pasadas, de modo que podemos pasar a un entorno de despliegue para poder enseñarlo a las partes interesadas, realizar pruebas más exhaustivas, o incluso, en casos de urgencia hacer un despliegue rápido.

Por supuesto, esto es el proceso base, a partir de aquí, podemos usarlo para muchas más cosas, como desplegar automáticamente la nueva versión, ejecutar conjuntos de pruebas más extensas, verificaciones de análisis de código, etc.
También, muy importante es el entorno que escojamos para todo este proceso, si usamos un entorno “viciado”, con multitud de referencias que no son las reales, dónde hemos realizado mil y una pruebas de librerías, puede que aunque podamos compilar, el resultado no sea el esperado. Así mismo, tener en cuenta que este es un entorno de compilación, no de ejecución, con lo que muchas veces es más que aceptable tener herramientas de desarrollo instaladas más allá del simple compilador, aunque es algo que yo siempre trato de evitar.

De hecho, con el objetivo de ejecución de pruebas en mente, lo ideal, es que el entorno, al menos en el que se ejecuten las pruebas, sea lo más parecido al entorno que usaremos en producción, aunque esto no siempre es posible, ya que pensad, por ejemplo, en el caso de una herramienta de cliente que va a ser ejecutada en multitud de configuraciones, no sería viable disponer de un entorno de integración continua para cada una de las configuraciones.

¿Herramientas? Aunque el pecado más habitual que solemos cometer los que estamos relacionados con alguna herramienta, es, inmediatamente buscar la herramienta para hacer todo esto, se puede partir desde lo más básico. En mi caso, que me muevo el 99% del tiempo en entornos Windows con .NET (el otro 1% es XCode y iPhone), se podría usar el compilador en línea, o MSBuild, junto con tareas programadas (aunque no será puramente integración continua), herramientas Open Source como NAnt, CruiseControl.NET, estas yo las he utilizado en el pasado, y la verdad que estaba muy contento. También hay herramientas comerciales de terceros, como el caso de TeamCity.

Si bien, yo en mis desarrollos siempre uso Team Foundation Server en su última versión, con esta herramienta tengo todo lo que necesito en un solo lugar, desde el control de código fuente, las compilaciones automatizadas, informes, gestión de tareas, integración continua. La gran ventaja que veo de contar con este entorno, es que de un modo muy sencillo, lo puedo poner todo a funcionar en su modo más básico, y a partir de ahí, empezar a mejorar mi proceso y a sacarle todo el jugo.

En el caso que me ocupa este artículo, la integración continua, con Team Foundation Server puedo configurar una compilación para cada check-in, que me realice una compilación de la rama o ramas que me interesan del control de código fuente (las afectadas por el check-in), la ejecución de las pruebas del listado de pruebas que tengo en mis proyectos de Visual Studio, el etiquetado del código fuente en relación a esta compilación, de modo que en cualquier momento puedo recuperar la versión del código que genera estos binarios, y por supuesto el almacenamiento de los binarios en una ubicación conocida por el equipo.

Además de todo esto, automáticamente me deja todo el resultado del proceso en el almacén de datos de Team Foundation Server, con lo que puedo, a posteriori, observar cuales han sido mis resultados de mi proceso de integración continua, y usar esos datos para poco a poco mejorar mi proceso, hacerlo más robusto e incorporar nuevos pasos o funcionalidades, como el despliegue automático, a medida que lo mejoro.

Como conclusión, empezar a pensar en vuestras aplicaciones y como añadir un proceso de integración continua, que os asegure la compilación y ejecución de pruebas correctamente a lo largo de todo el proceso, no sólo el último día.

Planificadlo acorde a vuestra capacidad actual, no os volváis locos intentando hacer un proceso de integración continua perfecto desde el principio, empezad poco a poco, con por ejemplo, automatizar la compilación mediante scripts, poned pruebas unitarias, ejecutadlo frecuentemente, preparar los entornos de compilación, automatizar esta compilación en cada subida de código al control de fuentes, y por supuesto, tomad datos del proceso y con esos datos, mejorar vuestro proceso día a día, o iteración a iteración.

En Genbeta Dev | La necesidad de las pruebas en las metodologías ágiles

Luis Fraile lleva trabajando en entornos Microsoft desde más de 10 años, empezando con Visual Basic 6, y posteriormente desde la primera versión del .NET Framework, habiendo participado en multitud de proyectos relacionados con estas tecnologías.


En los últimos años, a parte de desarrollar, también se ha dedicado a ayudar a equipos a la hora de abordar procesos de metodologías ágiles, especialmente en entornos Microsoft con tecnologías como Team Foundation Server. También es colaborador habitual de la revista Dotnetmania, así como ponente en eventos, a nivel nacional, relacionados con gestión de ciclo de vida y Team Foundation Server.

Puedes seguirlo en Twitter: @lfraile

Sus blogs son: lfraile.net y geeks.ms/blogs/lfraile


Portada de Genbeta