¿Cómo mantiene el código de desarrollo y el código de producción? [cerrado]

136

¿Cuáles son las mejores prácticas y reglas generales a seguir mientras se mantiene el código? ¿Es una buena práctica tener solo el código listo para producción en la rama de desarrollo, o debería estar disponible el último código no probado en la rama de desarrollo?

¿Cómo mantienen ustedes su código de desarrollo y su código de producción?

Editar - Pregunta complementaria - ¿Su equipo de desarrollo sigue el protocolo "commit-tan-pronto-como-posible-y-a menudo-incluso-si-el-código-contiene-errores-menores-o-está-incompleto" o "commit- ¿ÚNICO protocolo de código perfecto mientras se confirma el código en la rama DESARROLLO?

Mohit Ranka
fuente
He respondido una pregunta similar (o bueno, una pregunta en ese mismo espacio / dirección) antes, por lo que es posible que desee consultar esta pregunta: ¿Cuáles son algunas buenas estrategias para permitir que las aplicaciones implementadas sean reparables?
Hasta el
@revo: espera ... ¿mi respuesta de 2008 está desactualizada? :) Supongo que sí. Han pasado más de 10 años: he editado mi respuesta.
VonC

Respuestas:

114

Actualización 2019:

En estos días, la pregunta se vería en un contexto usando Git, y 10 años de usar ese flujo de trabajo de desarrollo distribuido (colaborando principalmente a través de GitHub ) muestra las mejores prácticas generales:

  • masteres la rama lista para implementarse en producción en cualquier momento: la próxima versión, con un conjunto seleccionado de ramas de características fusionadas master.
  • dev(o rama de integración, o ' next') es aquella en la que la rama de características seleccionada para la próxima versión se prueba en conjunto
  • maintenance(o hot-fix) es la rama de uno de los actuales arreglos evolución de liberación / errores, con posibles fusiones atrás a devy omaster

Ese tipo de flujo de trabajo (donde no se combinan deva master, pero donde se fusionan única rama función para dev, a continuación, si es seleccionado, para master, con el fin de ser capaz de soltar fácilmente presentará ramas no está listo para la próxima versión) se implementa en el Git repositorio en sí, con el flujo de trabajo (una palabra, ilustrada aquí ).
Ver más en rocketraman/gitworkflow. La historia de hacer esto vs Desarrollo basado en troncos se observa en los comentarios y discusiones de este artículo de Adam Dymitruk .

https://github.com/rocketraman/gitworkflow/raw/master/docs/images/topicgraduation.png

(fuente: Gitworkflow: un manual orientado a tareas )

Nota: en ese flujo de trabajo distribuido, puede confirmar cuando lo desee y enviar a una rama personal algo de WIP (Work In Progress) sin problema: podrá reorganizar (git rebase) sus confirmaciones antes de hacerlas parte de una rama característica.


Respuesta original (octubre de 2008, hace más de 10 años)

Todo depende de la naturaleza secuencial de su gestión de lanzamiento

Primero, ¿está todo en su baúl realmente para el próximo lanzamiento ? Puede descubrir que algunas de las funciones desarrolladas actualmente son:

  • demasiado complicado y aún necesita ser refinado
  • no listo a tiempo
  • interesante pero no para este próximo lanzamiento

En este caso, el enlace troncal debe contener cualquier esfuerzo de desarrollo actual, pero una rama de lanzamiento definida antes de la próxima versión puede servir como rama de consolidación en la que solo se fusiona el código apropiado (validado para la próxima versión) y luego se fija durante la fase de homologación, y finalmente congelado a medida que entra en producción.

Cuando se trata de código de producción, también debe administrar sus ramas de parches , teniendo en cuenta que:

  • el primer conjunto de parches podría comenzar antes de lanzarse a producción (lo que significa que sabrá que entrará en producción con algunos errores que no puede corregir a tiempo, pero puede iniciar el trabajo para esos errores en una rama separada)
  • las otras ramas de parches tendrán el lujo de comenzar con una etiqueta de producción bien definida

Cuando se trata de la rama de desarrollo, puede tener una troncal, a menos que tenga otros esfuerzos de desarrollo que necesite hacer en paralelo como:

  • refactorización masiva
  • prueba de una nueva biblioteca técnica que podría cambiar la forma en que llama a las cosas en otras clases
  • comienzo de un nuevo ciclo de lanzamiento donde se deben incorporar importantes cambios arquitectónicos.

Ahora, si su ciclo de desarrollo-lanzamiento es muy secuencial, puede seguir como sugieren las otras respuestas: un tronco y varias ramas de lanzamiento. Eso funciona para proyectos pequeños donde todo el desarrollo seguramente irá a la próxima versión, y solo puede congelarse y servir como punto de partida para la rama de lanzamiento, donde pueden tener lugar parches. Ese es el proceso nominal, pero en cuanto tienes un proyecto más complejo ... ya no es suficiente.


Para responder el comentario de Ville M.:

  • tenga en cuenta que la rama de desarrollo no significa 'una rama por desarrollador' (lo que desencadenaría 'fusionar locura', ya que cada desarrollador tendría que fusionar el trabajo de otro para ver / obtener su trabajo), sino una rama de desarrollo por desarrollo esfuerzo.
  • Cuando esos esfuerzos deben fusionarse nuevamente en el tronco (o cualquier otra rama "principal" o de lanzamiento que defina), este es el trabajo del desarrollador, no , repito, NO, el SC Manager (que no sabría cómo resolver cualquier fusión conflictiva). El líder del proyecto puede supervisar la fusión, lo que significa asegurarse de que comience / termine a tiempo.
  • a quien elijas para hacer la fusión, lo más importante es:
    • para tener pruebas unitarias y / o entorno de ensamblaje en el que puede implementar / probar el resultado de la fusión.
    • haber definido una etiqueta antes del comienzo de la fusión para poder volver al estado anterior si dicha fusión resulta demasiado compleja o bastante larga para resolver.
VonC
fuente
1
@ Adam Gracias por la edición, y lo siento por no establecer la atribución adecuada antes.
VonC
¡Decir ah! Sin preocupaciones. Has hecho tanto por la comunidad aquí, que casi no tienes la culpa de nada. ¡Estoy feliz de que haya personas como tú que trabajen tanto en beneficio de todos en todo el mundo!
Adam Dymitruk
43

Usamos:

  • rama de desarrollo exclusivamente

hasta que el proyecto esté cerca de su finalización, o si estamos creando una versión histórica (por ejemplo, demostración del producto, versión de presentación), luego (regularmente) ramificamos nuestra rama de desarrollo actual en:

  • rama de liberación

No hay nuevas características en la rama de lanzamiento. Solo los errores importantes se corrigen en la rama de lanzamiento, y el código para corregir estos errores se reintegra en la rama de desarrollo.

El proceso de dos partes con un desarrollo y una rama estable (lanzamiento) nos hace la vida mucho más fácil, y no creo que podamos mejorar ninguna parte introduciendo más ramas. Cada rama también tiene su propio proceso de compilación, lo que significa que cada dos minutos se genera un nuevo proceso de compilación y, por lo tanto, después de un registro de código, tenemos un nuevo ejecutable de todas las versiones y ramificaciones de compilación en aproximadamente media hora.

De vez en cuando también tenemos sucursales para un único desarrollador que trabaja en una tecnología nueva y no probada, o que crea una prueba de concepto. Pero generalmente solo se hace si los cambios afectan muchas partes de la base de código. Esto ocurre en promedio cada 3-4 meses y dicha rama generalmente se reintegra (o desecha) dentro de uno o dos meses.

En general, no me gusta la idea de que cada desarrollador trabaje en su propia sucursal, porque "saltas y te mueves directamente al infierno de integración". Yo recomendaría encarecidamente que no lo haga. Si tiene una base de código común, todos deberían trabajar juntos en ella. Esto hace que los desarrolladores sean más cautelosos acerca de sus registros, y con experiencia cada codificador sabe qué cambios están potencialmente rompiendo la compilación y, por lo tanto, las pruebas son más rigurosas en tales casos.

En la pregunta temprana de check-in:

Si solo necesita que se registre el CÓDIGO PERFECTO , en realidad no se debe registrar nada. Ningún código es perfecto, y para que el QA lo verifique y pruebe, debe estar en la rama de desarrollo para que se pueda construir un nuevo ejecutable.

Para nosotros, eso significa que una vez que el desarrollador haya probado y completado una característica, esta se registrará. Incluso puede registrarse si hay errores conocidos (no fatales), pero en ese caso las personas que se verían afectadas por el error Generalmente informado. El código incompleto y de trabajo en progreso también se puede registrar, pero solo si no causa ningún efecto negativo obvio, como bloqueos o interrupción de la funcionalidad existente.

De vez en cuando, un código combinado inevitable y el registro de datos harán que el programa sea inutilizable hasta que se haya creado el nuevo código. Lo menos que hacemos es agregar un "ESPERE PARA CONSTRUIR" en el comentario de check-in y / o enviar un correo electrónico.

steffenj
fuente
1
Lo voté. Esto es similar a lo que hacemos, pero estamos haciendo todos los cambios en el desarrollo y luego intentamos fusionar esas correcciones de errores en la rama de lanzamiento. No funciona. Sin embargo, creo que si cambiamos para hacer todas las correcciones de errores en la versión y fusionarnos en el desarrollo, eso lo solucionará.
TheCodeMonk
2
Usted implica que el control de calidad prueba la rama de desarrollo, ¿no sería mejor que revisen la rama de lanzamiento? De esa manera, podría comenzar a trabajar en mi nueva función loca que no se incluirá en la próxima versión (y podría romper algo), mientras que en ese momento QA probará el código existente sin que interfiera mi nueva función
BornToCode
15

Por lo que vale, así es como lo hacemos.

La mayor parte del desarrollo se realiza en el tronco, aunque las características experimentales o las cosas que pueden romper el sistema tienden significativamente a tener su propia rama. Esto funciona bastante bien, ya que significa que cada desarrollador siempre tiene la última versión de todo en su copia de trabajo.

Significa que es importante mantener el tronco en un estado de funcionamiento vago, ya que es perfectamente posible romperlo por completo. En la práctica, eso no sucede a menudo y rara vez es un problema significativo.

Para una versión de producción, ramificamos troncales, dejamos de agregar nuevas funciones y trabajamos en la corrección de errores y en la prueba de la ramificación (fusionando regularmente en la troncal) hasta que esté lista para su lanzamiento. En ese momento, hacemos una fusión final en el tronco para asegurarnos de que todo esté allí, y luego lo liberamos.

El mantenimiento se puede realizar en la rama de lanzamiento según sea necesario, y esas correcciones se pueden combinar fácilmente en el tronco.

No afirmo que este sea un sistema perfecto (y todavía tiene algunos agujeros, no creo que nuestra gestión de lanzamientos sea un proceso lo suficientemente apretado todavía), pero funciona lo suficientemente bien.

Dan
fuente
funciona lo suficientemente bien y también es lo suficientemente simple para los desarrolladores de código solo-no-vcs-druids.
Matthieu
12

¿Por qué nadie todavía menciona esto? Un exitoso modelo de ramificación Git .

¡Es para mí el último modelo de ramificación!

Si su proyecto es pequeño, no use todo el tiempo todas las ramas diferentes (quizás podría omitir ramas de características para características pequeñas). Pero de lo contrario, ¡es la forma de hacerlo!

modelo de ramificación

Philippe
fuente
44
Sí, excepto si a menudo es demasiado complejo / completo, como lo ilustra scottchacon.com/2011/08/31/github-flow.html .
VonC
Estoy de acuerdo. Comprenda el modelo de ramificación de flujo de git (que resuelve muchos problemas) y simplifíquelo para satisfacer sus necesidades. Y el flujo de GitHub requiere una implementación rápida, pero eso no siempre es posible ... Es más o menos el modelo de ramificación que usamos en mi proyecto (para simplificar las cosas), pero nos enfrentamos a un caso en el que nos hubiera encantado usar el modelo de git-flow: (y eso nos puso en una gran mierda :(
Philippe
1
A mi modo de ver, esto básicamente copia todo lo que VonC dijo aproximadamente 1 año antes (en su respuesta), ¡pero de una manera más detallada y con buenas fotos!
cregox
6

Código de desarrollo en sucursales, código en vivo etiquetado en Trunk.

No es necesario que exista una regla de "comprometer solo el código perfecto"; todo lo que el desarrollador se pierda debe ser recogido en cuatro lugares: la revisión del código, la prueba de ramificación, la prueba de regresión, la prueba de control de calidad final.

Aquí hay una explicación más detallada paso a paso:

  1. Realice todo el desarrollo en una rama, comprometiéndose regularmente a medida que avanza.
  2. Revisión independiente del código de los cambios una vez que se complete todo el desarrollo
  3. Luego pase la rama a Pruebas.
  4. Una vez completada la prueba de la rama, combine el código en la rama Release Candidate.
  5. La rama de Release Candidate se prueba de regresión después de cada fusión individual.
  6. Las pruebas finales de control de calidad y UA se realizaron en RC después de que todas las ramas de desarrollo se fusionaron.
  7. Una vez que se pasan QA y UAT, combine la rama de liberación en la rama MAIN / TRUNK.
  8. Finalmente, etiquete el Troncal en ese punto e implemente esa etiqueta en Live.
Peter Boughton
fuente
3

Resolvemos este problema separando completamente el código de producción (el tronco principal) del código de desarrollo (donde cada desarrollador tiene su propia rama).

No se permite ningún código en el código de producción antes de que se haya verificado a fondo (por QA y revisores de código).

De esta manera no hay confusión sobre qué código funciona, siempre es la rama principal.

Grimtron
fuente
2

Ah, sí, otra cosa: guardamos el código que no es de producción (es decir, el que NUNCA se lanzará, por ejemplo, scripts de herramientas, utilidades de prueba) en cvs HEAD. Por lo general, debe estar claramente marcado para que nadie lo libere "accidentalmente".

MarkR
fuente
2
tal vez esto sería mejor como una edición de la respuesta anterior.
Richard Harrison el
66
Dijo CVS. :-)
Hasta el
2

Desarrollamos en tronco que luego se ramifica cada dos semanas y se pone en producción. Solo los errores críticos se corrigen en la rama, el resto puede esperar otras dos semanas.

Para troncal, la única regla es que un commit no debe romper nada. Para administrar el código wip y el código no probado, solo agregamos declaraciones if apropiadas para facilitar el encendido y apagado.

Básicamente, sería posible ramificar el tronco en cualquier momento y ponerlo en producción.

John Nilsson
fuente
0

Uso git y tengo 2 ramas: master y maint

  • maestro - código de desarrollo
  • maint - código de producción

cuando lanzo el código a producción, lo etiqueto y fusiono master para mantener rama rama de . Siempre despliegue desde la rama de mantenimiento . Parches de la rama de desarrollo Los selecciono para mantener la rama e implementar parches.

Vitalie
fuente
0

Tenemos una rama de "lanzamiento" que contiene lo que está actualmente en producción o se implementará en breve (ya pasó la mayoría de QA)

Cada proyecto, o en algunos casos otra unidad, tiene su propia rama que se ramifica desde su lanzamiento.

Los desarrolladores del proyecto comprometen los cambios en la propia sucursal de su proyecto. Periódicamente, la versión se fusiona nuevamente en una rama de desarrollo.

Una vez que todos los paquetes de trabajo en la rama son QA'd (prueba de unidad, prueba del sistema, revisión de código, revisión de QA, etc.), la rama se fusiona con la rama de lanzamiento. Las nuevas compilaciones se crean desde la rama de lanzamiento, y la validación final ocurre en esa versión.

El proceso es básicamente correcto hasta que se descubre un problema después de haber realizado una fusión. Si un WP se "atasca" después de haber sido fusionado, lo retiene todo hasta que se arregle (no podemos hacer otra versión hasta que se libere la bloqueada).


También es algo flexible: un cambio muy trivial podría ocurrir directamente en la rama de lanzamiento si se lanzara en una escala de tiempo muy corta (como 1-2 días más o menos).

Si un cambio se aplica directamente a producción por algún motivo (un problema de producción crítico que afecta al cliente y que requiere un cambio de código inmediato para solucionarlo), esos cambios se volverían a colocar en BRANCH_RELEASE. Eso casi nunca sucede.

MarkR
fuente
0

Depende del proyecto. Nuestro código web se registra de manera bastante consistente, mientras que nuestro código de aplicación solo se registra si se compila. Me di cuenta de que esto es bastante similar a cómo lanzamos las cosas. Las cosas web suben siempre que pueden mientras las aplicaciones alcanzan una fecha límite difícil. Sin embargo, no he visto una pérdida de calidad en ninguno de los métodos.

icco
fuente