Close

¿Git o SVN? Nuance Healthcare se decantó por un modelo de creación de ramas de Git

Primer plano de Nicola Paolucci
Matt Shelton

Experto en desarrollo


Esta es una entrada de invitado de Matt Shelton, de Nuance Healthcare. Esta es la primera entrada de una serie sobre la migración de su equipo de Subversion a Git, los motivos por los que la llevaron a cabo y qué se encontraron durante el proceso. Matt también habla sobre este tema en Atlassian Summit 2015. En esta serie aborda con más contexto todo lo que no pudo decir en su charla de 30 minutos.

Contexto


Mi equipo forma parte del área de salud de Nuance. Estamos repartidos entre un par de oficinas y sedes en la Costa Este de Estados Unidos y una oficina en Pune. Desarrollamos servicios web de Java para ofrecer soluciones de PLN[1] en el mercado sanitario.

Los consumidores de nuestros servicios son mayoritariamente otras empresas de software del sector sanitario (incluyéndonos a nosotros), como proveedores de registros electrónicos de salud y empresas dedicadas al análisis de datos médicos. Vendemos algunos productos directamente a los hospitales, y los usuarios finales de las aplicaciones van desde médicos hasta el personal encargado de la facturación de servicios médicos. La gente corriente como tú y yo nunca usaremos el software que mi equipo compila.

Llevamos un tiempo combinando productos de gestión del ciclo de vida de las aplicaciones. Comenzamos con una combinación de Rally Enterprise y Seapine TestTrack Pro, trabajamos intensamente durante unos 14 meses con Rational Team Concert y, finalmente, migramos por completo a los recursos de Atlassian (Jira, Confluence, Bamboo, Crucible y Bitbucket). También usamos Subversion 1.4/1.5 y nuestra herramienta de SCM con una estructura de tronco, ramas y etiquetas bastante normal. Hemos usado Maven desde siempre para gestionar nuestros proyectos de compilación y dependencias, y hace un tiempo pasamos de Jenkins a Bamboo para aplicar la integración continua (CI) y poder así utilizar integraciones más estrechas con Jira y sus funciones flexibles de desarrollo e implementación de agentes. Todo lo que usamos ahora está implementado a nivel local por varias razones[2].

bases de datos
Material relacionado

Cómo mover un repositorio de Git completo

Logotipo de Bitbucket
VER LA SOLUCIÓN

Aprende a usar Git con Bitbucket Cloud

¿Git o SVN?


Ofrecemos soporte para unos diez productos de cuatro familias de productos, y los propietarios de estos productos siempre quieren tener prioridad y obtener ayuda rápidamente. No quiero que esto parezca una queja porque está muy bien estar tan solicitado, pero eso también implica publicar a un ritmo un tanto extraño y tener que cambiar de dirección en medio de los sprints[3].

Nuestro proceso de desarrollo a veces era caótico. Las conversaciones con mi equipo solían ser así:

Yo: Tenemos que enviar ya la versión 1.8.0 a control de calidad para hacer pruebas de regresión y que el cliente X pueda pasar a la beta la semana que viene. Desarrollador: Yo aún estoy con ABC-123, que está en el tronco. Necesito más tiempo. Yo: X no necesita ABC-123. Podríamos incluirlo en la próxima publicación. Desarrollador: Pero es que hace semanas que estoy con ello. Además, no está claro desde donde se puede crear una nueva rama para lanzar la publicación. Yo: Pues tendrás que incorporar todos los cambios a mano. Tienes unas dos horas, si no el control de calidad no podrá terminar a tiempo.

Soy muy duro, lo sé. Nunca he querido serlo (y aquí estoy exagerando un poco para dejar claro lo que quiero decir), pero es cierto que teníamos que averiguar cómo sacar el código temporalmente de un sitio para poder lanzar la publicación y luego volver a ponerlo para la siguiente publicación[4]. Y esto pasaba continuamente.

Algunos estaréis pensando que Subversion admite ramas, y es cierto. Algunas veces las usamos con SVN 1.4 y 1.5. La ramificación funciona muy bien en SVN, pero la fusión puede ser un auténtico quebradero de cabeza. Y, aunque no hay duda de que SVN ha ido mejorando, sabíamos que había una opción mejor para nosotros. Por eso, cuando tuvimos que decidirnos por SVN o Git, apostamos por Git.

Un breve apunte: estuvimos mirando la versión más reciente de SVN, que en ese momento era la 1.8, para ver si podía resolver nuestros problemas, pero no quedamos completamente satisfechos. Un grupo de colegas trabaja con una gran configuración de Perforce que parecía ofrecer muchas de las cosas que necesitábamos, pero no era posible asumir los costes de la licencia. También nos interesamos por Mercurial pero, al final, la experiencia que ya tenía el equipo con Git nos convenció de que ese era el camino a seguir.

No estoy tratando de dorar la píldora, pero las herramientas de Atlassian van de fábula para los equipos que usan Git. Otras herramientas de SCM funcionan bien y nuestra integración con SVN era suficiente en el sentido de que nos vinculaba con el punto en el que se habían hecho cambios relacionados con una determinada historia de usuario. Sin embargo, la capacidad de integración para los equipos que usan Bitbucket[5] es mucho más sólida y natural en la interfaz de Jira Software y en la experiencia de desarrollo, y lo mismo pasa con Bamboo.

Sabiendo esto, y después de haber visto algunas demostraciones espectaculares en Atlassian Summit 2013, animé al equipo a ir a por ello. Nadie se opuso, y ya teníamos las licencias para hacer el cambio.

Escoger un modelo de ramificación de Git


Después de decidirnos por este cambio, el primer reto fue decidir qué modelo de ramificación de Git implementaríamos para el equipo. El micrositio sobre Git de Atlassian y esta magnífica presentación de Atlassian Summit 2013 explican con detalle qué es un modelo de ramificación. En pocas palabras, describe cómo usarás las ramas en Git para tu flujo de trabajo de desarrollo.

En SVN, teníamos un modelo de ramificación que llamaré "crea una rama cuando te des cuenta de que necesitas una" y que funcionaba así:

  • El código más reciente estaba en trunk, y las publicaciones del tronco tenían la numeración A.B.0- {build}.
  • Si había que corregir algo en una publicación basada en tronco (por ejemplo, si había un error en la compilación 1.2.0-64), se creaba una rama y desde allí publicábamos las compilaciones A.B.C.- {build}, donde C se iba incrementando con cada publicación. Es posible que estas ramas nunca existieran para una publicación A.B determinada, e incluso podía haber más de una.
  • También etiquetábamos cada publicación en un directorio de etiquetas.

Un inciso sobre las versiones: hace muchos años, cuando empecé en esto de la gestión de un equipo de desarrollo, nuestro ingeniero de publicación tenía un sistema de control de versiones que era, por decirlo de algún modo, muy poco intuitivo. Básicamente, cada publicación era un parche de la anterior (a.B.N), sin respetar el punto desde el que se había originado el parche. Para averiguar de dónde venía algo y, en casi todos los casos, el orden de publicación, tenías que consultar svn log. Teníamos el árbol impreso en una pared como referencia. Además, los números de publicación de cara al usuario suelen ser 3.0, 3.1, 3.5, 4.0 o algún otro número previsible para el cliente. Pero hay que recordar que mi equipo crea servicios web, no un producto en una caja. Nuestras API son un contrato. Hace unos años, tomé la decisión de que las compilaciones de mi equipo y, por tanto, sus publicaciones, siguieran las reglas de las versiones semánticas. He tenido que defender varias veces esta postura con los directivos, pero ahora todo el mundo entiende por qué las reglas son las que son y no hemos vuelto atrás. Además, los socios aprecian esa claridad.

Antes he hablado de un problema que teníamos cuando, al trabajar en una publicación (por ejemplo, la 1.2.0), se acercaba la fecha de publicación y aún no habíamos terminado con una función. Teníamos que incorporar ese código, lanzar la publicación, bifurcar en branches/1.2.1 y luego fusionar el código con la esperanza de que a nadie se le hubiera roto el disco duro[6].

Quitar una función completa de un tronco compartido es un fastidio. Todo el mundo odiaba tener que hacerlo. El comando svn blame puede ser útil, al igual que cualquier herramienta potente de detección de cambios, pero usarlo se hace pesado. A menudo me lo tomaba como algo personal y pensaba que mi mala planificación nos había llevado a no tenerlo todo listo antes de una publicación[7]. Mi equipo estuvo lidiando con esto durante bastante tiempo.

A veces corregíamos de más para evitar complicaciones y pedíamos a los desarrolladores que se sentaran de brazos cruzados durante un par de días (una congelación del código virtual, por así decirlo), para que no contamináramos el tronco antes de una publicación.

Así que sabíamos que necesitábamos, al menos, ramas de funciones. Se puede usar un sencillo modelo de ramificación de Git: una rama principal para producción y una rama de función para cada función, error, etc. Los equipos tienen que gestionar el orden de fusión para asegurarse de que lo que se lance a la rama principal sea lo que debe estar en la publicación. Esto es básicamente lo mismo que teníamos antes con un mejor aislamiento de las funciones, pero lo que queríamos era más libertad.

En nuestro entorno, a menudo necesitamos tener varias versiones en producción, y es posible que tengamos que corregir defectos en una publicación dos o tres veces anterior a lo que estamos haciendo en este momento. Por eso, además de las ramas de función, también necesitábamos algún tipo de rama de publicación que nos permitiera corregir incidencias de las publicaciones anteriores. Hace las correcciones en ramas de soporte de larga duración y, luego, las fusiona en el flujo de ramas para que lleguen a todas las ramas de soporte.

Su modelo era realmente interesante e hicimos varias pruebas con él para ver si se ajustaba a nuestras necesidades. Para este equipo, la "aplicación definitiva" es la que permite la fusión continua de una corrección en la rama de desarrollo. Este concepto nos gustó, pero cada vez que lo probábamos nos encontrábamos con un problema u otro en nuestras dependencias de Maven. Además, no estábamos seguros de que querer hacer siempre una fusión directa del trabajo de una versión a otra. A veces teníamos que implementar la misma corrección de formas ligeramente diferentes en las distintas versiones, por lo que una fusión directa no era posible.

Parte del equipo estaba muy a favor de una variante de este modelo conocida como "git-flow". git-flow es un conjunto de convenciones de nomenclatura de ramas y pautas de fusión creadas por Vincent Driessen. Al equipo le pareció una opción muy intuitiva y su estructura nos gustó, ya que eliminaba muchas preguntas de tipo: "¿Qué tengo que hacer si quiero conseguir X?". En general, las respuestas eran muy obvias. Pero, en lugar de explicar qué es git-flow, te recomiendo que consultes el tutorial de Atlassian.

Lo único que nos quedaba por solucionar con git-flow era qué hacer con las publicaciones en producción que llevaban tanto tiempo. Como la rama main no deja de evolucionar, no podíamos usar el flujo de trabajo de corrección de git-flow para corregir un error de una publicación anterior. Y, por otro lado, no siempre queríamos una rama de soporte.

La mayoría de las veces, bastaría con parchear la última publicación en producción para corregir un error; la rama de soporte solo hace falta si hay que retroceder más o cuando hay que mantener la compatibilidad por algún motivo. Analizamos más a fondo este último caso y determinamos los criterios para decidir cuándo usar una rama de soporte en lugar de una corrección y una mejora de versión menor:

1. Cuando el código no se puede volver a fusionar sin más en el desarrollo.

2. Cuando el partner o el cliente no pueden gestionar un cambio de interfaz de la última publicación.

3. Cuando hay una dependencia interna que no se puede cambiar.[8]

Ambos paquetes de extensión de git-flow[9] admiten el concepto de rama de soporte, que no forma parte del borrador original de git-flow pero es lo suficientemente conocido como para justificar su inclusión.

git-flow ofrecía un flujo de trabajo que nos gustaba con las herramientas que necesitábamos. En la siguiente publicación, explicaré lo que pasó cuando intentamos aplicarlo en un proyecto de prueba de concepto que usamos para representar nuestro proceso de desarrollo. Fue toda una experiencia de aprendizaje.

[1]: Procesamiento de lenguaje natural. TE LEEMOS LA MENTE (bueno, la verdad es que no).

[2]: Las ofertas en la nube de Atlassian son muy atractivas, pero por ahora necesitamos tener nuestros servidores y datos cerca. Nosotros no trabajamos mucho con información médica protegida, pero nuestro software sí, por eso es importante garantizar que sea lo más seguro posible.

[3]: ¡Chiss! No se lo digas a Ken Schwaber.

[4]: Además, esto podía pasar solo unos días más tarde.

[5]: Se llamaba Stash hasta que Atlassian le cambió el nombre.

[6]: Sé que podíamos sacarlo de la confirmación anterior. Estaba de broma.

[7]: Por lo general, ese no era el caso. Lo que pasaba es que el plazo de otra persona se adelantaba y teníamos que reaccionar rápido.

[8]: Esta es una de las cosas de las que no puedo hablar en mi blog. Créeme, tengo motivos para no hacerlo.

[9]: El paquete original de Vincent Driessen ya no se actualiza. Lo que sí que se actualiza periódicamente es una nueva bifurcación.


Footnotes

[1]: Natural Language Processing. WE CAN READ YOUR THOUGHTS. (No. Not really.)

[2]: There is a lot that is attractive about Atlassian's cloud offerings, but we need to keep our fingers wrapped tightly around our servers and data for the time being. While we don't personally need to do much with PHI data, our software does and it's important to keep it as secure as possible.

[3]: Shhhh... don't tell Ken Schwaber.

[4]: Which might have only been a few days later anyway.

[5]: Formerly known as Stash. Hello, Atlassian Fall Rebranding!

[6]: I know we could always pull it out of the previous commit. I was kidding.

[7]: This wasn't usually the case - generally it was because someone else's timeframe moved up and we had to react quickly.

[8]: This is one of those things I can't get into on my own blog. Just trust me. "Reasons".

[9]: The original package by Vincent Driessen isn't being maintained any longer. A new fork, however, is regularly updated.

Matt Shelton
Matt Shelton

Matt Shelton promueve y aplica la metodología DevOps. Supervisa la prestación de los servicios de DevOps (entre otros servicios relacionados) que ofrece Atlassian en el continente americano. Ya rara vez publica algo en su blog, y se centra en crear la próxima generación de promotores de formas más adecuadas de trabajar.


Compartir este artículo
Tema siguiente

Lecturas recomendadas

Consulta estos recursos para conocer los tipos de equipos de DevOps o para estar al tanto de las novedades sobre DevOps en Atlassian.

Gente que colabora utilizando un muro lleno de herramientas

Blog de Bitbucket

Ilustración de Devops

Ruta de aprendizaje de DevOps

Demostraciones de funciones con expertos de Atlassian del Centro de demostraciones

Cómo funciona Bitbucket Cloud con Atlassian Open DevOps

Suscríbete para recibir el boletín de DevOps

Thank you for signing up