2008-10-28 9 views
27

Digamos que tiene varias ramas de mantenimiento para las 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.Refactorización y ramas de desarrollo concurrente

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

Respuesta

22

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

  1. El código en la línea externa no ha cambiado y el parche se aplica sin conflicto.
  2. El código en la línea externa ha cambiado y se aplica el parche, pero con una combinación manual necesaria.
  3. El código en la línea externa 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 las rutas 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. La introducción de un nuevo problema para un posible defecto en el maletero debe ser un último recurso para el desarrollador de mantenimiento.

Uno de los beneficios de tener desarrolladores de mantenimiento que intenten aplicar parches a la troncal actualizada 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.

+0

Muchas posibilidades abiertas. ¡Gran respuesta, Greg! –

+0

Por supuesto, uno PODRÍA aplicar la refactorización a las ramas de mantenimiento también. Pero en 99 de 98 casos esto será mucho trabajo. –

+0

@Jens: a menos que planee _desarrollar_ las ramas de "mantenimiento", solo arregle lo que está roto. Sus clientes quieren estabilidad, no código limpio. –

1

En el punto en que sus ramas de mantenimiento ya no son 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.

+0

Las ramas de mantenimiento representan probablemente código enviado real y por lo tanto no puede ser abandonado. Las reparaciones se deben aplicar a esas sucursales porque hay un cliente que necesita esa corrección y está ejecutando esa versión del código. –

1

Crea una rama de mantenimiento y haz que actúe como un búfer entre el tronco y las ramas de versión.

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

No creo que haya una bala de plata, sin embargo. 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.

+0

¡Similar a la respuesta de Elie! –

0

Solo puedo hacer eco de lo que otros han dicho, mientras enfatizo el verdadero dolor en el a $$ en 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 trabajo.

2

La única respuesta que he podido encontrar es crear una rama de mantenimiento de enlace justo 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 intentar algo como MolhadoRef (blog article about MolhadoRef and Refactoring-aware SCM), si puede encontrar un sistema equivalente listo para su 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.

3

Esto es, en última instancia, una cuestión de comunicación en equipo, en lugar de una simple cuestión 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.

Luego, debe alertar a todo el equipo sobre el problema.

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

  1. Si las ramas de mantenimiento se utilizan con poca frecuencia, dicen que el código publicado es bastante madura y libre de errores, usted puede decidir sobre un congelamiento de 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 baúl se refactura, pero antes de limpiarlo, pulirlo, etiquetarlo y soltarlo, revise la base de datos de errores, particularmente los elementos arreglados en las ramas pero no en el baúl. ¿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 resuelvan todos los problemas conocidos, se puede liberar la nueva versión y se pueden cerrar las ramas antiguas.

+0

Es de suponer que las viejas ramas no pueden cerrarse cuando se libera una nueva versión, ya que las versiones antiguas todavía están soportados para los clientes que utilizan esas versiones. –

2

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

  • Paso 1: Comience a refaccionar 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 ser capaces de verificar que la migración de las antiguas a las nuevas funciona correctamente, pero este paso probablemente todavía incurrirá en costos de pruebas/control de calidad.

  • 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 llamante puede ser comprometido/liberado uno a la vez.

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

cuenta que cuando el API es público y no controla las personas que llaman (empresas como Microsoft, por ejemplo), es posible que nunca será capaz de ir más allá de la etapa 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.

1

Esto puede ser una sugerencia muy laboriosa, pero lo primero que me viene a la mente es unir todo al tronco. 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 y en el 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 forma maximizaría la calidad de todas sus sucursales y haría que su refactorización se extendiera por todas las ramas que se ramificaría después de la refactorización. Esta sería una buena forma de unir a su equipo para la fusión.

1

veo dos caminos diferentes para hacer frente a este:

1.

cambios significativos en el tronco (como una refactorización importante) no se debe hacer 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 realizar cambios en las ramas de mantenimiento, se pueden fusionar de nuevo en la cajuela.

2.

crear una rama de las ramas de mantenimiento (una rama para cada uno). 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 refacciones en la cajuela y combínelas en las ramas de 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 el equilibrio 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.

0

¿Tienes que tener que se están trabajando en muchas ramas?

¿El trabajo en el maletero solo comenzó cuando lo hizo porque el plan del proyecto decía que la versión actual estaría lista 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 demasiadas versiones antiguas debido a la brecha antes de que la siguiente versión principal sea demasiado grande?

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

respuesta al comentario:

Microsoft todavía es compatible con Windows XP a pesar de que Vista está fuera

es muy cierto, sin embargo Microsoft no siguen apoyando la ventana XP SP1 a pesar de que 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.

+0

"Abordar el motivo por el que los clientes no actualizan" no es realmente un consejo relevante. Puede haber muchas razones, la # 1 es "El cliente quiere eso y eso es por lo que están pagando". Este es el pan y la mantequilla del desarrollo de software. Microsoft todavía es compatible con Windows XP, aunque Vista ya no funciona. –

2

Dado que gran parte del costo de corregir un error está reproduciendo el problema y probando la solución. ¿Puedes 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?

0

creo que su mejor opción es tener iterativo refactorización. 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 con mucha frecuencia va a ser mucho menos trabajo que fusionar ramas grandes que difieren bastante. Cuanto más a menudo te fusione, menos trabajo tendrás que hacer al final.

0

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

  1. aparece tanto en el tronco como en la rama principal, lo arreglamos en el tronco y luego fusionamos el cambio en la rama de mantenimiento (que puede suceder limpiamente o requiere más trabajo, en el cual caso decidamos si no es mejor tener el error solucionado en la versión más reciente solamente).
  2. es sólo en la rama de mantenimiento, es probable que algún rey de la solución en el maletero y vamos a scenation número uno.
0

Como Greg pointed hay varios escenarios posibles.

Agregaría un caso (2.5) donde se requiera la fusión manual, pero ya que ha movido un método fuera de su ubicación original y luego aplicado algunos cambios, se hace difícil fusionar, especialmente si la "base" el código también se modificó 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.

Hemos desarrollado una herramienta llamada Xmerge (cross-merge) que es un primer paso hacia la fusión refactor-conscientes. Todavía no es automático, pero ayuda a lidiar con fusiones difíciles que involucran código movido. It's described here y ya está integrado en Plastic SCM 2.7.

Estamos trabajando en: detección de movimiento automático y también ser capaz de "fusión cruz" hacia múltiples archivos de destino (que mover el código a otro archivo, que también es bastante común).

Cuestiones relacionadas