Estamos haciendo proyectos, pero reutilizamos mucho código entre los proyectos y tenemos muchas bibliotecas que contienen nuestro código común. A medida que implementamos nuevos proyectos, encontramos más formas de factorizar código común y ponerlo en bibliotecas. Las bibliotecas dependen unas de otras, y los proyectos dependen de las bibliotecas. Cada proyecto, y todas las bibliotecas utilizadas en ese proyecto, deben usar la misma versión de todas las bibliotecas a las que se refieren. Si lanzamos una pieza de software tendremos que corregir errores y tal vez agregar nuevas funciones durante muchos años, a veces durante décadas. Tenemos alrededor de una docena de bibliotecas, los cambios a menudo abarcan más de dos, y varios equipos trabajan en varios proyectos en paralelo, realizando cambios concurrentes en todas estas bibliotecas.
Recientemente cambiamos a git y configuramos repositorios para cada biblioteca y cada proyecto. Usamos stash como un repositorio común, hacemos cosas nuevas en las ramas de características, luego hacemos solicitudes de extracción y las fusionamos solo después de la revisión.
Muchos de los problemas con los que tenemos que lidiar en los proyectos requieren que hagamos cambios en varias bibliotecas y el código específico del proyecto. Estos a menudo incluyen cambios en las interfaces de la biblioteca, algunos de los cuales son incompatibles. (Si cree que esto suena sospechoso: interactuamos con el hardware y ocultamos hardware específico detrás de las interfaces genéricas. Casi cada vez que integramos el hardware de otro proveedor nos encontramos con casos en los que nuestras interfaces actuales no se anticipaban, por lo que tenemos que refinarlos). ejemplo, imagine un proyecto P1
usando las bibliotecas L1
, L2
y L3
. L1
también usa L2
y L3
, y L2
usa L3
también. El gráfico de dependencia se ve así:
<-------L1<--+
P1 <----+ ^ |
<-+ | | |
| +--L2 |
| ^ |
| | |
+-----L3---+
Ahora imagine que una característica para este proyecto requiere cambios P1
y L3
que cambia la interfaz de L3
. Ahora agregue proyectos P2
y P3
en la mezcla, que también se refieren a estas bibliotecas. No podemos permitirnos cambiarlos a la nueva interfaz, ejecutar todas las pruebas e implementar el nuevo software. Entonces, ¿cuál es la alternativa?
- implementar la nueva interfaz en
L3
- hacer una solicitud de extracción
L3
y esperar la revisión - fusionar el cambio
- crear una nueva versión de
L3
- comience a trabajar en la función
P1
haciendo referencia aL3
la nueva versión, luego implemente la función enP1
la rama de funciones - hacer una solicitud de extracción, revisarla y fusionarla
(Me he dado cuenta de que se me olvidó para cambiar L1
y L2
para la nueva versión. Y yo no sé ni dónde pegar esto en, ya que tendría que hacerse en paralelo con P1
...)
Este es un proceso tedioso, propenso a errores y muy largo para implementar esta función, requiere revisiones independientes (lo que hace que sea mucho más difícil de revisar), no se escala en absoluto y es probable que nos saque del negocio porque se estancan tanto en el proceso que nunca hacemos nada.
Pero, ¿cómo empleamos la ramificación y el etiquetado para crear un proceso que nos permita implementar nuevas funciones en nuevos proyectos sin demasiados gastos generales?