tutorial hub how guide docs control version-control refactoring release branch merge

version control - hub - ¿Cómo maneja la tensión entre la refactorización y la necesidad de fusionarse?



how to use github io (6)

Donde trabajo, nos mantenemos con la refactorización en la rama principal. Si las fusiones se vuelven complicadas, solo tienen que tratarse de manera ad-hoc, todas son factibles, pero ocasionalmente toman un poco de tiempo.

Nuestra política al entregar una nueva versión es crear una sucursal en nuestro VCS y manejarla a nuestro equipo de control de calidad. Cuando este último da luz verde, etiquetamos y lanzamos nuestro producto. La rama se mantiene para recibir (solo) correcciones de errores para que podamos crear versiones técnicas. Esas correcciones de errores se fusionaron posteriormente en el tronco.

Durante este tiempo, el tronco ve el trabajo de desarrollo principal y está potencialmente sujeto a cambios de refactorización.

El problema es que hay una tensión entre la necesidad de tener un troncal estable (para que la combinación de correcciones de errores tenga éxito, por lo general no puede si el código ha sido extraído, por ejemplo, a otro método o trasladado a otra clase) y la necesidad de refactorizarlo al introducir nuevas funciones.

La política en nuestro lugar es no hacer ninguna refactorización antes de que pase suficiente tiempo y la rama sea lo suficientemente estable. Cuando este es el caso, uno puede comenzar a hacer cambios de refactorización en el tronco, y las correcciones de errores se deben confirmar manualmente tanto en el tronco como en la rama.

Pero esto significa que los desarrolladores deben esperar bastante tiempo antes de comprometerse en el tronco cualquier cambio de refactorización, ya que esto podría romper la fusión posterior de la rama al tronco. Y tener que portar manualmente errores de la rama al tronco es doloroso. Me parece que esto dificulta el desarrollo ...

¿Cómo manejas esta tensión?

Gracias.


Este es un problema práctico real. Empeora si tiene varias versiones que necesita admitir y ha ramificado para cada una. Aún peor si tienes una rama de I + D genuina también.

Mi preferencia era permitir que el troncal principal avanzara a su ritmo normal y no esperar porque en un entorno donde los tiempos de liberación eran importantes comercialmente, nunca podría argumentar que deberíamos permitir que el código se estabilice ("¿qué? lo liberó en un estado inestable? ").

La clave era asegurarse de que las pruebas unitarias que se crearon para las correcciones de errores se transfirieron cuando el error se migró a la rama principal. Si los cambios de su nuevo código son simplemente re-factoring, entonces las pruebas antiguas deberían funcionar igual de bien. Si los cambios son tales que ya no son válidos, entonces no puede simplemente arreglar el puerto en ningún caso y deberá pedirle a alguien que reflexione sobre la corrección en el nuevo flujo de código.

Después de algunos años gestionando este tipo de problema, llegué a la conclusión de que probablemente necesite 4 secuencias de código como mínimo para proporcionar soporte y cobertura adecuados, y una colección de procesos bastante rigurosos para administrar el código a través de ellos. Es un poco como el problema de poder dibujar cualquier mapa en 4 colores.

Nunca encontré ninguna literatura realmente buena sobre este tema. Inevitablemente estará vinculado a su estrategia de lanzamiento y a los SLA que firma con sus clientes.

Adición: También debo mencionar que era necesario escribir la fusión de sucursales como hitos específicos en el cronograma de publicación de la rama principal. No subestime la cantidad de trabajo que podría implicar unir sus sucursales si tiene una colección de desarrolladores trabajadores que realizan las funciones de implementación de su trabajo.


Tal vez nuestro problema proviene del hecho de que tenemos ramas que deben tener una vida bastante larga (hasta 18 meses), y hay muchas soluciones que deben hacerse contra ellas.

Asegurarse de que solo nos ramifiquemos de un código extremadamente estable probablemente sea útil, pero no será tan fácil ... :(


Creo que la tensión puede controlarse agregando los siguientes ingredientes a su proceso de desarrollo:

  1. Integración continua
  2. Pruebas funcionales automatizadas (supongo que ya cuenta con pruebas unitarias)
  3. Entrega automatizada

Con la integración continua, cada compromiso implica una construcción donde se ejecutan todas las pruebas de la unidad y te alarma si algo sale mal. Empieza a trabajar más con head y es menos propenso a la bifurcación de la base de código.

Con las pruebas funcionales automatizadas, puede probar su aplicación con solo hacer clic en el botón. Generalmente, dado que estas pruebas toman más tiempo, se realizan todas las noches. Con esto, el rol clásico del control de versiones comienza a perder importancia. Usted no toma la decisión sobre cuándo lanzar según la versión y su vencimiento, sino que es más una decisión comercial. Si ha implementado las pruebas unitarias y funcionales y su equipo está presentando el código probado, la cabeza siempre debe estar en un estado que pueda liberarse. Los errores son continuamente descubiertos y corregidos y lanzados entregados, pero este no es más un proceso cíclico, sino continuo.

Probablemente tengas dos tipos de detractores, ya que esto implica cambiar algunas prácticas arraigadas desde hace mucho tiempo. En primer lugar, el cambio de paradigma de la entrega continua parece contraintuitivo para los gerentes. "¿No nos arriesgamos a enviar un error importante?" Si echas un vistazo a las distribuciones de Linux o Windows, esto es exactamente lo que están haciendo: empujar lanzamientos hacia los clientes. Y dado que cuenta con un conjunto de pruebas automatizadas, los peligros disminuyen aún más.

Luego, equipo o departamento de QA. (¡Algunos argumentarían que el problema es su existencia en sí misma!) En general, serán reacios a automatizar las pruebas. Significa aprender una herramienta nueva y, a veces, complicada. Aquí, lo mejor es predicar haciéndolo. Nuestro equipo de desarrollo comenzó a trabajar en integraciones continuas y, al mismo tiempo, redactó el conjunto de pruebas funcionales con Selenium . Cuando el equipo de QA vio la herramienta en acción, fue difícil oponerse a su implementación.

Finalmente, el jueves es que el proceso que describí no es tan simple como añadir 3 ingredientes a su proceso de desarrollo. Implica un cambio profundo en la forma en que desarrolla el software.


Tal vez Git (u otro DVCS) sea mejor para manejar las fusiones al código actualizado gracias al hecho de que (realmente) administran los cambios en lugar de simplemente comparar archivos ... Como dice Joel :

Con control de versiones distribuidas, las fusiones son fáciles y funcionan bien. Así que puede tener una sucursal estable y una sucursal de desarrollo, o crear sucursales de larga duración para su equipo de control de calidad, donde prueban cosas antes de la implementación, o puede crear sucursales efímeras para probar nuevas ideas y ver cómo funcionan.

No intentado todavía, sin embargo ...


Donde trabajo, creamos ramas de trabajo temporales, de vida corta (menos de un día) durante cada cambio no trivial (adición de funciones o corrección de errores). El tronco es estable e (idealmente) potencialmente liberable todo el tiempo; solo los elementos hechos se fusionan en él. Todo lo que se compromete desde el tronco se fusiona en las ramas de trabajo todos los días; esto se puede automatizar en gran medida (usamos Hudson, Ant y Subversion). (Este último punto porque generalmente es mejor resolver cualquier conflicto más temprano que tarde, por supuesto).

El modelo actual que usamos estuvo influenciado en gran medida por un excelente artículo ( que he conectado antes ) por Henrik Kniberg: Control de versiones para múltiples equipos ágiles .

(En nuestro caso, tenemos dos equipos scrum trabajando en una base de código, pero he llegado a pensar que este modelo puede ser beneficioso incluso con un equipo).

Hay algo de sobrecarga sobre la bifurcación adicional y la fusión, pero no demasiado, realmente, una vez que te acostumbras y mejoras con las herramientas (por ejemplo, svn merge --reintegrate es útil). Y no, no creo una rama de temperatura siempre, por ejemplo, para refactorizaciones más pequeñas y de bajo riesgo (sin relación con los elementos principales actualmente en funcionamiento) que pueden completarse fácilmente con una confirmación en el enlace troncal.

También mantenemos una rama de versiones antiguas en la que se reparan errores críticos de vez en cuando. Es cierto que puede haber trabajo de fusión manual (a veces tedioso) si alguna parte particular del código ha evolucionado significativamente en el tronco en comparación con la rama. (Es de esperar que se convierta en un problema menor a medida que avanzamos hacia la liberación continua de incrementos desde el tronco (internamente), y dejando que el marketing y la administración de productos decidan cuándo quieren hacer una versión externa).

No estoy seguro si esto responde su pregunta directamente, o si puede aplicar esto en su entorno (con el equipo de control de calidad separado y todo), pero al menos puedo decir que la tensión que describe no existe para nosotros y estamos libre de refactorizar siempre que sea ¡Buena suerte!