¿La integración continua implica un repo VCS monolítico?

7

Soy parte de un pequeño equipo que desarrolla varias aplicaciones internas para nuestra empresa. Estamos en un proceso de volvernos más ágiles, esto incluye especialmente muchas pruebas automatizadas. Ahora estamos en una situación en la que, para las una o dos aplicaciones en las que hemos trabajado más recientemente, generalmente realizamos cambios pequeños y reversibles, realizamos muchas pruebas y las implementamos bastante rápido sin mucha intervención humana.

Considero que todavía estamos muy lejos de hacer IC "real". Para las una o dos aplicaciones mencionadas anteriormente, probablemente podamos acercarnos mucho a esto muy pronto. Sin embargo, me está costando mucho imaginar cómo se verá nuestra configuración, en algún momento en el futuro en el que hemos comenzado a usar CI para la mayoría de nuestro código heredado.

Supongamos que tenemos varias aplicaciones independientes, que se pueden implementar de forma independiente en diferentes servidores. También tenemos un código compartido que es usado por muchos de ellos, y que queremos usar de manera consistente entre ellos. Esto incluye funciones de utilidad, código que impone elementos como una interfaz consistente en algunas partes de todas las aplicaciones y las definiciones de ORM para nuestra base de datos (compartida en todas las aplicaciones).

Veo dos alternativas, ninguna de las cuales parece muy fácil o elegante:

  • Todo el código se fusiona en un enorme repositorio. La implementación significa ejecutar todas las pruebas para todos los códigos, las pruebas de integración para todo y las pruebas de aceptación para todas las aplicaciones, antes de implementar todo de una vez. Esto parece hacer que el despliegue sea un acuerdo mucho más grande de lo que era antes, contrariamente a la filosofía de CI, que sugiere que debería ser rápido y fácil. También significa que no tenemos ninguna separación entre las diferentes partes de nuestra base de código, con cosas que nunca funcionan juntas en el mismo repositorio para siempre, solo porque ambas dependen de una tercera cosa.
  • Mantenemos separadas cada aplicación y cada componente del código compartido. La implementación significa probar la última versión de un componente de forma exhaustiva, antes de 'soltarlo' en un sistema operativo que consiste en todos los demás componentes. Esto parece un diseño más limpio. Sin embargo, parece implicar que tenemos que administrar las dependencias y el control de versiones para todas estas cosas. Cada prueba de integración / aceptación debe tener algún conocimiento previo de las versiones de los otros componentes con los que se utilizará y puede tolerar. En otras palabras, aunque todos los componentes se vuelven mucho más confiables, tenemos que preocuparnos más por cómo encajan las piezas y los errores de integración. Cuando las piezas de las que todo lo demás depende del cambio, existe la posibilidad de rotura en cualquier lugar.

La solución a este dilema es probablemente hacer una versión flexible de CI, donde los componentes individuales se prueban extensivamente y se implementan rápidamente, pero nos atenemos a las grandes versiones de las utilidades y el esquema de base de datos. Pero realmente parece que hay muchos beneficios de un CI / CD adecuado que nos estaríamos perdiendo. No es una solución estéticamente agradable, y no buscamos satisfacer a nuestros jefes porque hemos marcado una casilla, pero queremos mejorar nuestras prácticas de trabajo.

¿Cómo deberíamos organizar el código para el CI adecuado y cuáles son las lecciones clave para aprender sobre la planificación y el diseño de la arquitectura, tanto para el código heredado como para el futuro código recién escrito?

    
pregunta jwg 25.09.2015 - 00:55

3 respuestas

6

Imagina tu código no como un sistema monolítico, sino como una serie de paquetes. Algunos paquetes dependen de otros. Algunos, como jQuery, son externos a su empresa; Otros son desarrollados por su empresa y hechos públicos; Otros, desarrollados por su compañía, eventualmente se hacen privados.

Por ejemplo, si desarrolla una aplicación web en Python, puede tener una dependencia con Flask, un popular marco web de Python, y con un montón de otros paquetes, tanto externos como internos.

¿Qué sucede con su CI cuando los desarrolladores de Flask lanzan una nueva versión? Derecho, nada Depende de usted ir y editar su archivo de proyecto que dice que de ahora en adelante, no está utilizando la versión x de Flask, sino la versión y . Una vez que lo haga, CI considera que el proyecto su ha cambiado e inicia todas las pruebas que garantizan que la aplicación aún funciona con la nueva versión de Flask. Si no lo hace, bueno, probablemente arreglará su aplicación , excepto en casos muy raros en los que realmente revela un error en el propio Flask.

La misma lógica se puede aplicar a cualquier código producido dentro de su empresa. Una biblioteca compartida se convierte en un paquete de Python, ya sea compartida a través de pypi : el repositorio de paquetes públicos de Python, o almacenada en un servidor privado pip que se puede usar solo dentro de su empresa.

Entonces deja particularmente claro lo que rompió la construcción. Cuando publica la nueva versión de un paquete A, CI ejecuta las pruebas correspondientes e indica si la versión contiene regresiones o no. Luego, si se encuentra un problema en la etapa cuando le pide a un paquete B que use la nueva versión del paquete A, es el paquete B el que rompió la compilación al ser incompatible con la nueva versión del paquete A: de la misma manera Es posible que su aplicación no sea compatible con una versión más reciente de Flask o jQuery.

Tenga en cuenta que no tiene que administrar realmente las dependencias: el sistema de empaquetado lo hace por usted. El único problema que requiere su intervención es la actualización de las referencias, es decir, la acción de indicar que un paquete determinado usará una versión diferente de otro paquete: si modificó un paquete que se usa mucho en su base de código, puede tómese un tiempo para rastrear y modificar todos los proyectos que lo utilizan.

En cuanto al control de versiones, realmente no importa. Puede tener un equipo trabajando con Git y otro trabajando con SVN. Tan pronto como los dos equipos acuerden usar pypi y elegir pip server (s) ¹ específicos para paquetes internos, todo estará bien. Del mismo modo, no debería importarte si los desarrolladores de Flask o jQuery usan Git, SVN, SourceSafe o TFS.

Nota: He usado un ejemplo del mundo de Python, pero la misma lógica también se puede aplicar a otros idiomas. Hay npm para Node.js, NuGet para los idiomas de .NET Framework, etc. También puede configurar administradores de paquetes privados.

Más información: Paquetes, dependencias e interacción entre equipos , mi artículo basado en esta pregunta.

¹ Nada lo obliga a tener un solo servidor de paquetes en su empresa. Diferentes equipos pueden desplegar sus propios servidores; la única restricción es que otros equipos deben conocer la ubicación del servidor para poder usar los paquetes.

    
respondido por el Arseni Mourzenko 25.09.2015 - 01:25
1

Los sistemas CI apoyan la organización del trabajo que realizan en proyectos. Por lo tanto, puede crear tantos proyectos de integración diferentes como necesite, y cada uno de ellos tendrá un conjunto de preferencias completamente diferente, que incluye, por supuesto, desde qué raíz del repositorio se debe retirar, dónde implementarlo, etc.

Dicho esto, si tiene módulos que tienen dependencias estrechas entre sí, entonces estos módulos deberían estar idealmente en el mismo repositorio.

Por "dependencias ajustadas" no me refiero a algo específico, pero como regla general, diría que si necesita realizar pruebas de integración entre ellas (en lugar de pruebas unitarias) entre ellos, entonces probablemente valga la pena llamarlo una dependencia estricta. .

Por "idealmente" quiero decir que los beneficios de mantenerlos en el mismo repositorio generalmente superan las desventajas. Pero, por supuesto, usted conoce mejor su código, por lo que es decisión suya.

    
respondido por el Mike Nakis 25.09.2015 - 01:40
1

También puede trabajar con una "alineación" de todos sus repositorios de componentes individuales (su segunda alternativa) de manera monolítica (consulte mi respuesta a esta Q para un posible enfoque), tratándolos como un mega-proyecto único, que en cierto sentido le permitiría ignorar el problema de la administración las dependencias entre los componentes (IMHO mucho más complejo).

Se consideraría que cada cambio en los componentes de código compartido afecta a todos los componentes que dependen de ellos. Esto le permitiría centrarse en probar las aplicaciones reales en lugar de realizar pruebas exhaustivas en los componentes compartidos (lo cual, en mi humilde opinión, no siempre puede garantizar para las aplicaciones que utilizan esas composiciones compartidas).

    
respondido por el Dan Cornilescu 27.09.2015 - 05:55