modelo desarrollo concurrente svn version-control refactoring branch

svn - modelo - Refactorización y ramas de desarrollo concurrente



modelo de desarrollo concurrente (14)

Supongamos que tiene varias ramas de mantenimiento para versiones existentes de su software. Algunos desarrolladores están realizando cambios directos en las ramas de mantenimiento y fusionándose periódicamente en el tronco. Ahora viene una extensa refactorización en la línea de código troncal, programada para una próxima versión principal. Pero esto hace que las ramas de mantenimiento sean fundamentalmente incompatibles con el código en el tronco, ya que pueden depender de un código que ya no existe, por ejemplo.

¿Cómo manejas esta situación en la práctica?


¿Tienes que tener tantas ramas trabajando?

¿El trabajo en el maletero solo comenzó cuando lo hizo porque el plan del proyecto decía que el lanzamiento actual estaría listo para enviarse, por lo tanto, se envió?

¿Tiene muchas sucursales de mantenimiento porque los clientes se niegan a actualizar a la última versión por alguna razón? Si es así, dirígete a la razón.

¿Tiene demasiados lanzamientos antiguos debido a la brecha antes de que el próximo lanzamiento principal sea demasiado grande?

¿Cobra a los clientes que no actualizarán más por mantenimiento, ya que le costó más?

Respuesta para comentar:

Microsoft todavía es compatible con Windows XP, aunque Vista está fuera

Es muy cierto, sin embargo, Microsoft aún no es compatible con Windows XP SP1 aunque XP SP3 está fuera.

Esto no es en blanco y negro, incluso si no puede dejar de admitir la versión anterior, es posible que pueda reducir el número de versiones anteriores que admite. El problema es que a Sales / Support le gusta decir que sí, pero que el desarrollo recibe el dolor, por lo que necesita poner a su gente de ventas / soporte a un lado.


Como señaló Greg, hay varios escenarios posibles.

Agregaría un caso (2.5) donde se requiera la fusión manual, pero como has movido un método lejos de su ubicación original y luego has aplicado algunos cambios, es difícil fusionarlo, especialmente si también se modificó el código "base". en la rama de "mantenimiento". Esto no es tan raro como suena, de hecho mover un método a una ubicación diferente y aplicar una pequeña corrección es bastante común.

Desarrollamos una herramienta llamada Xmerge (cross-merge) que es un primer paso hacia la fusión consciente de refactor. Todavía no es automático, pero ayuda a lidiar con fusiones difíciles que involucran código movido. Se describe aquí y ya está integrado en Plastic SCM 2.7.

Estamos trabajando en: detección automática de movimiento y también en la posibilidad de "combinar cruzados" para múltiples archivos de destino (mueve el código a otro archivo, que también es bastante común).


Considero que es responsabilidad del desarrollador de mantenimiento de la sucursal fusionar el cambio apropiado en el estado actual del enlace troncal. Hay varias posibilidades:

  1. El código en el enlace no ha cambiado y el parche se aplica sin conflicto.
  2. El código en el tronco ha cambiado y el parche se aplica, pero con una fusión manual necesaria.
  3. El código en el maletero ha cambiado completamente y el parche no se puede aplicar. El desarrollador debe evaluar si existe el mismo defecto en el tronco y aplicar una solución equivalente si es necesario.

Los casos 1 y 2 son los caminos de desarrollo de mantenimiento habituales. El Caso 3 es el caso que está considerando, donde el código de troncal no puede aceptar el parche de mantenimiento de ninguna forma. Si el desarrollador no puede determinar si el mismo problema puede existir en el tronco, entonces debe ingresar un problema en el sistema de seguimiento de problemas. Este problema indicaría a los desarrolladores de troncales que consideren el motivo del parche en la rama de mantenimiento y si aún existe el mismo defecto. Ingresar un nuevo problema por un posible defecto en el maletero debe ser un último recurso para el desarrollador de mantenimiento.

Uno de los beneficios de que los desarrolladores de mantenimiento intenten aplicar parches al tronco actualizado es aumentar su familiaridad con la nueva base de códigos. Eventualmente, se quedarán sin trabajo de mantenimiento y necesitarán trabajar con el nuevo baúl. Tener al menos un nivel básico de familiaridad será de gran beneficio.


Cree una rama de mantenimiento y haga que actúe como un búfer entre trunk y las versiones-ramas.

Los cambios en las ramificaciones de versión entran en la rama de mantenimiento y luego se propagan al tronco solo si pueden y viceversa.

Aunque no creo que haya una bala de plata. A medida que las sucursales divergen cada vez más, se volverán incompatibles, por lo que debe tener en cuenta durante cuánto tiempo los apoyará. De lo contrario, podría terminar corrigiendo errores más de una vez, pero de forma ligeramente diferente para las distintas ramas.


Creo que tu mejor opción es tener una refactorización iterativa . En lugar de hacer toda la refactorización en una gran toma en una sucursal privada, hágalo una fase a la vez. Realice algunos cambios en la rama y cuando sepa que son estables, combínelos con el tronco. Los desarrolladores que trabajan en otras ramas serían responsables de mantener continuamente su rama actualizada con el tronco.

Combinar un pequeño conjunto de cambios va a ser mucho menos efectivo que fusionar grandes ramas que difieren bastante. Cuanto más a menudo te fusione, menos trabajo tendrás que hacer al final.


Dado que gran parte del costo de corregir un error es reproducir el problema y probar la solución. ¿Puede escribir una prueba automatizada que funcione en todas las ramas, incluso si la corrección de código debe hacerse de manera diferente para cada rama?


En última instancia, se trata de una cuestión de comunicación de equipo, en lugar de una simple pregunta de bifurcación / fusión.

El primer paso, como en todos esos casos, es darse cuenta de que tiene un problema. Esto es algo que has hecho.

Entonces, debes alertar a todo el equipo sobre el problema.

Una vez que hayas hecho eso, creo que hay dos caminos diferentes:

  1. Si las ramas de mantenimiento se usan con poca frecuencia, digamos que el código liberado es bastante maduro y no tiene errores, puede decidir sobre la congelación de un código. Cada desarrollador debe terminar lo que está trabajando para el 32 de septiembre y fusionar esos cambios nuevamente en el tronco. Las ramas deberían estar cerradas o congeladas. Entonces, el trabajo puede continuar en el tronco y el nuevo software puede ser lanzado.

  2. Si hay cambios y correcciones frecuentes o urgentes en las sucursales, este problema es más complicado. Todavía tiene que haber un congelamiento de código, o el tronco será golpeado varias veces. Pero aquí, los desarrolladores aún deben arreglar las cosas mientras tanto y llevarlas a los clientes. Sugiero que cada cambio en las ramas después de la congelación del código troncal se registre en la base de datos de seguimiento de fallas (una necesidad en cada situación) con una indicación especial de que esto se corrigió en la rama N pero aún no se fusionó con la troncal. Esto requiere un registro cuidadoso para que cada detalle relevante sea recordado.

    Después de que el tronco sea refactorizado, pero antes de limpiarlo, pulirlo, etiquetarlo y soltarlo, revise la base de datos de errores, particularmente los elementos fijados en las ramas pero no en el tronco. ¿Siguen siendo relevantes? Ahora es el momento de cambiar el código nuevamente, si es necesario. Puede significar un doble trabajo por un tiempo breve, pero es de esperar que el código sea mucho más fácil de mantener ahora.

    Una vez que se resuelven todos los problemas conocidos, se puede lanzar la nueva versión y se pueden cerrar las antiguas.


En el momento en que sus ramas de mantenimiento ya no sean compatibles con el tronco principal, sería el momento de crear nuevas ramas para ese fin. Es decir, al comienzo del gran proyecto, se asegura de que todos sus desarrolladores estén al tanto de que la nueva funcionalidad viene en el tronco principal, para que puedan elegir mejor dónde implementar las correcciones. Presumiblemente, si los cambios de código que se producen en el tronco principal son tan importantes que hacen que el mantenimiento no sea compatible, entonces el mantenimiento debe incorporarse al tronco principal.


En la práctica, es posible que deba hacer un trabajo extra para que sus nuevos cambios sean compatibles con versiones anteriores.

  • Paso 1: comience a refactorizar el componente. Con cada paso, mantenga la interfaz anterior, pero haga que migre las llamadas a la nueva implementación. Tenga en cuenta que esto se puede hacer en varios pasos a medida que se construye la nueva interfaz / API. Las pruebas unitarias deben poder verificar que la migración de las antiguas a las nuevas funciona correctamente, pero es probable que este paso todavía provoque una sobrecarga de pruebas / QA.

  • Paso 2: la nueva versión está en producción; asegúrese de que todos lo sepan. En este punto, no se agregan nuevas características a la versión anterior, y todas las personas que llaman nuevas (o modificadas) usan la nueva versión.

  • Paso 3: Encuentre todo (utilice herramientas para hacer esto) que llame a la interfaz anterior y cambie todo para llamar a la nueva interfaz. Esto probablemente también implica una gran cantidad de pruebas / control de calidad. Sin embargo, cada persona que llama puede ser comprometida / liberada de a una por vez.

  • Paso 4: en este punto, la nueva versión está en vivo, y no quedan personas que accedan a la versión anterior. Eliminarlo de forma segura.

Tenga en cuenta que cuando la API es pública y no controla a las personas que la llaman (empresas como Microsoft, por ejemplo), es posible que nunca pueda pasar del paso 2.

Este proceso puede ser lento y requiere mucha disciplina, comunicaciones y pruebas. Pero en los casos en que la alternativa es jugar catch-up / integration para siempre, podría ser una opción razonable.


En nuestro proyecto, no corregimos principalmente los cambios en las ramas de mantenimiento de versiones. Si hay un error y

  1. ocurre tanto en el tronco como en la rama principal, lo reparamos en el tronco y luego fusionamos el cambio en la rama de mantenimiento (que puede suceder limpiamente o requiere más trabajo, en cuyo caso decidimos si no es mejor hacerlo). tener el error corregido en la versión más nueva solamente).
  2. está solo en la rama de mantenimiento, probablemente haya algún rey de arreglo en el tronco y vayamos a la escena número uno.

Esta puede ser una sugerencia muy laboriosa, pero lo primero que me viene a la mente es fusionar todo de nuevo en el maletero. Los cambios de todos se fusionan a la copia del tronco y los mantienen juntos. Luego, refactoriza en el baúl como quieras. Ahora tiene un baúl de trabajo, con todas las correcciones juntas.

Desafortunadamente, esto significaría que cualquier corrección en las ramas de mantenimiento tendría que ser unida al tronco central. Me doy cuenta de que esto sería un montón de trabajo, pero creo que esto permitiría que todo se refactorice, y cualquier mejora en las ramas de mantenimiento pertenecería a la rama principal. Puedo ser ingenuo acerca de esto, pero realmente no he trabajado en un proyecto de producción, y tampoco sé exactamente qué hay en las ramas de mantenimiento. Me imagino que esto haría que el maletero esté completamente actualizado y todas sus mejoras de mantenimiento se integrarían en el maletero.

Me imagino que hacerlo de esta manera maximizaría la calidad de todas tus sucursales y harías que tu refactorización se extienda por todas las ramas que ramas después de la refactorización. Esta sería una buena forma de unir a su equipo para la fusión.


La única respuesta que he podido encontrar es crear una rama de mantenimiento trunk antes de comenzar a refactorizar. Mantiene esta nueva rama como si fuera una troncal, fusionando los cambios desde y hacia las ramas de liberación de forma normal. En el futuro, debes tener cuidado al mezclar los cambios de las bases fuente antiguas y nuevas.

La otra alternativa es probar algo como MolhadoRef ( artículo de blog sobre MolhadoRef y SCM con Refactoring-aware ), si puede encontrar un sistema equivalente listo para la producción que satisfaga sus necesidades. Esto es, en teoría, control de fuente consciente de refactorización. No he investigado en mucho tiempo, pero recuerdo que todavía estaba lejos de ser algo más que un documento de investigación y una prueba de concepto.


Solo puedo hacer eco de lo que otros han dicho, mientras enfatizo el dolor real en el a $$ en el que se pueden formar las colas de parches.

Si tiene una ventana de fusión predefinida (y revestida de hierro), solo debe tener dos semanas de infierno para enfrentar.


Veo dos maneras diferentes de abordar esto:

1.

No se deben realizar cambios significativos en el tronco (como una refactorización mayor) en el maletero. Deben hacerse en una rama y fusionarse nuevamente en el tronco cuando estén lo suficientemente estables.

Periódicamente, los cambios en el tronco deben fusionarse con las otras ramas de mantenimiento. La razón por la que solo se fusiona la refactorización en el tronco cuando es estable es porque estos se fusionarán en las ramas de mantenimiento. Sin embargo, si no hay oportunidad de hacer estos cambios estables, entonces la opción 2 sería mejor.

Después de que se hayan realizado cambios en las ramas de mantenimiento, pueden fusionarse de nuevo en el tronco.

2.

Cree una rama de las ramas de mantenimiento (una rama para cada una). Esto se usará para fusionar el tronco con cada rama de mantenimiento. (Tenga en cuenta que el uso de SVN externos o equivalentes se debe utilizar para limitar el número de ramas de mantenimiento).

Realice todas las refactorizaciones en el baúl y combínelas con las ramas de mantenimiento. Cuando suelte o piense que el tronco está estable, fusione estas ramas de las liberaciones de mantenimiento en sus ramas respectivas. Estos pueden a su vez fusionarse de nuevo en el tronco.

En efecto, cada rama de mantenimiento se convierte en un "tronco secundario".

Tenga en cuenta que este escenario resalta la compensación entre el mantenimiento futuro y el mantenimiento inicial. Cuantas más ramas y diferencias tenga en su código, más mantenimiento por adelantado se requiere. La parte buena es que el mantenimiento incremental es mucho más fácil.