Mantenga cientos de sucursales personalizadas sobre la sucursal maestra


140

Actualmente tenemos una rama maestra para nuestra aplicación PHP en un repositorio compartido. Tenemos más de 500 clientes suscriptores de nuestro software, la mayoría de los cuales tienen personalización para diferentes propósitos, cada uno en una sucursal separada. La personalización podría ser un nombre de campo de texto diferente, una función o módulo totalmente nuevo, o nuevas tablas / columnas en la base de datos.

El desafío al que nos enfrentamos es que a medida que mantenemos estos cientos de sucursales personalizadas y distribuimos a los clientes, de vez en cuando brindamos nuevas funciones y actualizamos nuestra sucursal maestra, y nos gustaría impulsar los cambios de la sucursal maestra a las sucursales personalizadas para actualizar ellos a la última versión.

Desafortunadamente, esto a menudo resulta en muchos conflictos en el código personalizado, y pasamos muchas horas revisando cada rama para resolver todos los conflictos. Esto es muy ineficiente, y hemos descubierto que los errores no son infrecuentes al resolver estos conflictos.

Estoy buscando una manera más eficiente de mantener nuestras sucursales de lanzamiento de clientes actualizadas con la sucursal maestra, lo que resultará en menos esfuerzo durante la fusión.


11
Lamento no dar una respuesta de "puedes usar la herramienta X", pero no hay una.
Carreras de ligereza en órbita el

3
O durante la compilación (que probablemente sea más común). Simplemente ... no completamente por separado las bases de código.
Carreras de ligereza en órbita

15
@FernandoTan: su síntoma visible puede ser el código, pero la causa principal de su enfermedad es la fragmentación de su producto, la cura debe provenir del enfoque del producto / mapeo de la capacidad del producto, no de la limpieza del código; eso eventualmente sucederá. He detallado más en mi respuesta: programmers.stackexchange.com/a/302193/78582
Alex S

8
Esto también podría ser un problema económico. ¿Realmente ganas dinero con esos 500 clientes? Si no, tiene que pensar demasiado en su modelo de precios y rechazar las solicitudes de cambio si el cliente no paga una tarifa adicional.
Christian Strempfer

13
Esto hizo que mi corazón se rompiera un poquito. Afortunadamente, otros ya están gritando las respuestas correctas; mi única recomendación adicional es que escriba esto y lo envíe a TheDailyWTF.
zxq9

Respuestas:


314

Estás abusando completamente de las ramas! Debe tener la personalización impulsada por la flexibilidad en su aplicación, no por la flexibilidad en el control de su versión (que, como ha descubierto, no está destinada / diseñada para este tipo de uso).

Por ejemplo, haga que las etiquetas de campo de texto provengan de un archivo de texto, no se codifiquen en su aplicación (así es como funciona la internacionalización). Si algunos clientes tienen características diferentes, haga que su aplicación sea modular , con límites internos estrictos regidos por API estrictas y estables, para que las características se puedan conectar según sea necesario.

La infraestructura central y las características compartidas solo deben almacenarse, mantenerse y probarse una vez .

Deberías haber hecho esto desde el principio. Si ya tiene quinientas variantes de producto (!), Arreglar esto será un gran trabajo ... pero no más que un mantenimiento continuo.


142
+1 para "Deberías haber hecho esto desde el principio". Este nivel de deuda técnica puede destruir una empresa.
Daenyth

31
@Daenyth: Francamente, con quinientas ramas personalizadas, me sorprende que aún no lo haya hecho. ¿Quién deja que las cosas se pongan tan mal? lol
ligereza corre en órbita el

73
@FernandoTan Lo siento muchísimo por ti ...
enderland

20
@FernandoTan: Yo también. :( ¿Tal vez debiste haber hecho más preguntas en la entrevista?;) Para ser claros, el "tú" en mi respuesta es la organización. Es una abstracción. No estoy buscando culpar a las personas.
Carreras de ligereza en órbita el

58
Primero obtenga más información: permita que los desarrolladores hagan una diferencia entre la versión actual y la rama personalizada. Entonces al menos sabes qué diferencias hay. Esa lista le permite ver dónde puede ganar la reducción más rápida de ramas. Si 50 tienen nombres de campo personalizados, concéntrese en eso y le ahorrará 50 ramas. Luego busca el siguiente. También puede tener algunos que no son restaurables, pero al menos la cantidad será menor y no crecerá más cuando obtenga más clientes.
Luc Franken

93

Tener 500 clientes es un buen problema, si hubiera pasado el tiempo por adelantado para evitar este problema con las sucursales, es posible que nunca haya podido seguir operando durante el tiempo suficiente para obtener clientes.

En primer lugar, espero que cobre a sus clientes lo suficiente como para cubrir TODOS los costos de mantener sus versiones personalizadas. Supongo que los clientes esperan obtener nuevas versiones sin tener que pagar para que sus personalizaciones se realicen nuevamente. Comenzaría por encontrar todos los archivos que son iguales en el 95% de sus sucursales. Ese 95% es la parte estable de su aplicación.

Luego, encuentre todos los archivos que solo tienen unas pocas líneas diferentes entre las ramas; intente introducir un sistema de configuración de modo que se puedan eliminar estas diferencias. Entonces, por ejemplo, en lugar de tener cientos de archivos con etiquetas de campo de texto que son diferentes, tiene 1 archivo de configuración que puede anular cualquier etiqueta de texto. (Esto no tiene que hacerse de una vez, solo configure la etiqueta de un campo de texto la primera vez que un cliente quiera cambiarla).

Luego pase a los problemas más difíciles utilizando el patrón de Estrategia, la inyección de dependencia, etc.

Considere almacenar json en la base de datos en lugar de agregar columnas para los propios campos del cliente; esto puede funcionar para usted si no necesita buscar estos campos con SQL.

Cada vez que verifique un archivo en una rama, DEBE diferenciarlo con main y justificar cada cambio, incluido el espacio en blanco. Muchos cambios no serán necesarios y se pueden eliminar antes del registro. Esto puede deberse a que un desarrollador tenga diferentes configuraciones en su editor para la forma en que se formatea el código.

Su objetivo es pasar primero de 500 sucursales con muchos archivos que son diferentes, a la mayoría de las sucursales que solo tienen unos pocos archivos que son diferentes. Sin dejar de ganar suficiente dinero para vivir.

Es posible que aún tenga 500 sucursales en muchos años, pero si son mucho más fáciles de administrar, entonces ha ganado.


Basado en el comentario de br3w5:

  • Podrías tomar cada clase que sea diferente entre clientes
  • Haga una "xxx_baseclass" que defina todos los métodos que se invocan en la clase desde fuera de ella
  • Cambie el nombre de la clase para que xxx se llame xxx_clientName (como subclase de xxx_baseclass)
  • Use la inyección de dependencia para que se use la versión correcta de la clase para cada cliente
  • ¡Y ahora para obtener una visión inteligente, br3w5 se le ocurrió! Use una herramienta de análisis de código estático para encontrar el código ahora duplicado y muévalo a la clase base, etc.

Solo haga lo anterior después de haber obtenido el grano fácil, y siga primero con algunas clases.


28
+1 por intentar proporcionar un enfoque para el problema real
Ian

35
Estaba realmente preocupado de que te felicitaras por tu respuesta, hasta que me di cuenta de que no eras el mismo @Ian que escribió la respuesta.
Theron Luhn

2
Tal vez deberían utilizar una herramienta de análisis de código estático para reducir lo que se duplican partes del código (después de la identificación de todos los archivos que son los mismos)
br3w5

1
También creando paquetes versionados para ayudar al equipo a rastrear qué cliente tiene qué versión del código
br3w5

1
Suena como una forma larga y sin aliento de decir "simplemente refactorice su código"
Roland Tepp

40

En el futuro, haga las preguntas de la prueba de Joel en su entrevista. Sería más probable que no entrasen en un choque de trenes.


Este es un, ah, cómo diremos ... realmente, muy mal problema tener. La "tasa de interés" de esta deuda técnica será muy, muy alta. Puede que no sea recuperable ...

¿Cuán integrados con el "núcleo" están estos cambios personalizados? ¿Puede convertirlos en su propia biblioteca y tener un solo "núcleo" y que cada cliente específico tenga su propio "complemento"?

¿O son todas estas configuraciones muy menores?

Creo que la solución es una combinación de:

  • Cambiar todos los cambios codificados en elementos basados ​​en la configuración. En este caso, todos tienen la misma aplicación principal, pero los usuarios (o usted) activan / desactivan funciones, establecen nombres, etc., según sea necesario
  • Mover la funcionalidad / módulos "específicos del cliente" para separar proyectos, por lo que en lugar de tener un "proyecto", tiene un "proyecto principal" con módulos que puede agregar / quitar fácilmente. Alternativamente, también puede hacer estas opciones de configuración.

Ninguno de los dos será trivial, ya que si terminó aquí con más de 500 clientes, es probable que no haya hecho una distinción real en esto. Espero que sus cambios al separar esto va a ser una tarea muy lenta.

También sospecho que tendrá problemas importantes para separar y clasificar fácilmente todo el código específico de su cliente.

Si la mayoría de sus cambios son específicamente diferencias de redacción, sugiero leer preguntas como esta sobre la localización del idioma. Ya sea que esté haciendo múltiples idiomas por completo o solo un subconjunto, la solución es la misma. Esto es específicamente PHP y localización.


1
Además, dado que esta será una tarea enorme (por decir lo menos), será un desafío significativo incluso convencer a sus gerentes de que inviertan grandes cantidades de tiempo y dinero en este problema. @FernandoTan Puede haber preguntas + respuestas en este sitio que pueden ayudar con este problema específico.
Radu Murzea

10
¿Qué pregunta de la prueba de Joel te habría dicho que la empresa está abusando de las sucursales?
SpaceTrucker

2
@SpaceTrucker: Bueno, "¿Haces compilaciones diarias?" podría haber ayudado Con 500 sucursales, probablemente no las tenían, o podrían haber mencionado que solo lo hacen para algunas sucursales.
sleske

17

Este es uno de los peores antipatrones que puedes usar con cualquier VCS.

El enfoque correcto aquí es convertir el código personalizado en algo impulsado por la configuración, y luego cada cliente puede tener su propia configuración, ya sea codificada en un archivo de configuración, o en una base de datos u otra ubicación. Puede habilitar o deshabilitar funciones completas, personalizar el aspecto de las respuestas, etc.

Esto le permite mantener una rama maestra con su código de producción.


3
Si hace esto, hágase un favor e intente utilizar el patrón de Estrategia tanto como sea posible. Esto hará que sea mucho más fácil mantener su código que si simplemente lo aplica if(getFeature(FEATURE_X).isEnabled())todo.
TMN

13

El propósito de las sucursales es explorar una posible vía de desarrollo sin arriesgarse a romper la estabilidad de la sucursal principal. Eventualmente deberían fusionarse de nuevo en un momento adecuado, o descartarse si conducen a un callejón sin salida. Lo que tienes no son tanto ramas, sino más bien 500 tenedores del mismo proyecto y tratar de aplicar los conjuntos de cambios vitales a todos ellos es una tarea sísifo.

En cambio, lo que debe hacer es tener su código central en vivo en su propio repositorio, con los puntos de entrada necesarios para modificar el comportamiento a través de la configuración e inyectar el comportamiento según lo permitan las dependencias invertidas .

Las diferentes configuraciones que tiene para los clientes pueden simplemente distinguirse entre sí por un estado configurado externamente (por ejemplo, una base de datos) o, si es necesario, vivir como repositorios separados, que agregan el núcleo como un submódulo.


66
Olvidó las ramas de mantenimiento, que son básicamente lo opuesto a las ramas que describió en su respuesta. :)
ligereza corre en órbita el

7

Todas las cosas importantes han sido propuestas por buenas respuestas aquí. Me gustaría agregar mis cinco peniques como sugerencia de proceso.

Me gustaría sugerirle que resuelva este problema a largo o mediano plazo y que adopte su política sobre cómo desarrollar el código. Intenta convertirte en un equipo de aprendizaje flexible. Si alguien permitió tener 500 repos en lugar de hacer que el software sea configurable, entonces es hora de preguntarse cómo ha trabajado hasta ahora y lo hará a partir de ahora.

Lo que significa:

  1. Aclare las responsabilidades de gestión del cambio: si un cliente necesita algunas adaptaciones, ¿ quién las vende, quién las permite y quién decide cómo se cambiará el código? ¿Dónde están los tornillos para girar si algunas cosas deben cambiar?
  2. Aclare el rol, quién en su equipo puede hacer nuevos repositorios y quién no.
  3. Intente asegurarse de que todos en su equipo vean la necesidad de patrones que permitan flexibilidad al software.
  4. Aclare su herramienta de administración: ¿cómo sabe rápidamente qué cliente tiene qué adopciones de código? Lo sé, alguna "lista de 500" suena molesto, pero aquí hay algo de "economía emocional", si quieres. Si no puede ver los cambios del cliente en poco tiempo, se siente aún más perdido y atraído como si tuviera que comenzar una lista. Luego, use esa lista para agrupar las características de la forma en que las respuestas de otras personas aquí le han mostrado:
    • agrupar clientes por cambios menores / mayores
    • grupo por tema cambios relacionados
    • agrupar por cambios fáciles de fusionar y cambios difíciles de fusionar
    • encuentre grupos de cambios iguales realizados en varios repositorios (oh sí, habrá algunos).
    • quizás lo más importante para hablar con su gerente / inversionista: agrupar por cambios costosos y cambios baratos .

Esto de ninguna manera pretende crear una atmósfera de mala presión en su equipo. Prefiero que aclare estos puntos primero y, donde sea que sienta el apoyo, organícelo junto con su equipo. Invita a personas amigables a la mesa para mejorar toda tu experiencia.

Luego, intente establecer una ventana de tiempo a largo plazo, donde cocine esta cosa en una pequeña llama. Sugerencia: intente fusionar al menos dos repositorios cada semana, y elimine al menos uno . Puede aprender que a menudo, puede fusionar más de dos ramas, a medida que adquiere rutina y supervisión. De esa manera, en un año puede manejar las peores (¿las más caras?) Sucursales, y en dos años puede reducir este problema para tener un software claramente mejor. Pero no espere más, ya que al final nadie "tendrá tiempo" para esto, pero usted es quien no lo permitirá más, ya que es el arquitecto del software.

Así es como trataría de manejarlo si estuviera en tu posición. Sin embargo, no sé cómo su equipo va a aceptar tales cosas, cómo el software realmente lo permite, cómo se le brinda soporte y qué es lo que aún tiene que aprender. Usted es el arquitecto de software, simplemente hágalo :-)


2
Buenos puntos sobre cómo abordar los problemas sociales / organizativos que acechan detrás de los problemas técnicos. Esto se pasa por alto con demasiada frecuencia.
sleske

5

En contraste con todos los que no lo dicen, asumamos una necesidad comercial real.

(por ejemplo, entregable es el código fuente, los clientes son de la misma línea de negocios y, por lo tanto, competidores entre sí, y su modelo de negocio promete mantener sus secretos en secreto)

Además, supongamos que su empresa tiene las herramientas para mantener todas las sucursales, es decir, mano de obra (digamos 100 desarrolladores dedicados a la fusión, suponiendo un retraso de lanzamiento de 5 días; o 10 desarrolladores suponiendo que el retraso de lanzamiento de 50 días está bien), o tal prueba impresionante automatizado que se funde automatizados están verdaderamente a prueba tanto a las especificaciones del núcleo y la especificación de extensión en cada rama, y por lo tanto sólo los cambios que no se funden "limpiamente" requieren la intervención humana. Si sus clientes pagan no solo por las personalizaciones sino también por el mantenimiento de las mismas, este puede ser un modelo comercial válido.

Mi pregunta (y negativa) es: ¿tiene una persona dedicada responsable de la entrega a cada cliente? Si usted es, digamos, una compañía de 10,000 personas, puede ser el caso.

Esto podría ser manejado por la arquitectura de complementos en algunos casos, digamos que su núcleo es troncal, los complementos podrían mantenerse en troncal o ramas, y la configuración para cada cliente es un archivo con un nombre único o se mantiene en la rama del cliente.

Los complementos pueden cargarse en tiempo de ejecución o incorporarse en tiempo de compilación.

Realmente muchos proyectos se hacen así, fundamentalmente el mismo problema aún se aplica: los cambios básicos simples son triviales para integrar, los cambios de conflicto deben revertirse o se necesitan cambios para muchos complementos.

Hay casos en que los complementos no son lo suficientemente buenos, es decir, cuando se deben ajustar tantas partes internas del núcleo que el recuento de la interfaz del complemento se vuelve demasiado grande para manejar.

Idealmente, esto se manejaría mediante programación orientada a aspectos , donde el enlace troncal es el código central y las ramas son aspectos (es decir, código adicional e instrucciones sobre cómo conectar los extras al núcleo)

Un ejemplo simple, puede especificar que la costumbre foose ejecute antes o después del núcleo klass.fooo que la reemplace, o que la envuelva y pueda cambiar la entrada o la salida.

Hay un montón de bibliotecas para eso, sin embargo, el problema de los conflictos de fusión no desaparece: AOP maneja las fusiones limpias y los conflictos aún necesitan la intervención humana.

Finalmente, este negocio realmente tiene que preocuparse por el mantenimiento de la sucursal , a saber, ¿la característica X específica del cliente es tan común que es más barato moverla al núcleo, a pesar de que no todos los clientes pagan por ella?


3

No está resolviendo la causa raíz de la enfermedad al observar el síntoma. El uso de un enfoque de 'gestión de código' es sintomático, pero no resolverá las cosas a largo plazo. La causa raíz es la falta de capacidades, características y sus extensiones y variaciones de producto 'bien administradas'.

Su código 'personalizado' no representa más que extensiones de las características y capacidades del producto y cambios en el campo de datos en otros.

Cuán extensas serán las características personalizadas, qué tan diferentes, qué contextualmente similares o no jugarán mucho en la "desinfección" de la base de código de su producto.

Más allá de cómo codifica y versiona, este es un lugar donde la gestión del producto, la arquitectura del producto y la arquitectura de datos entran en juego. Seriamente.

Porque, al final del día, el código no es más que su oferta de negocios y características / servicios de productos a sus clientes. Eso es lo que le pagan a su empresa.

Obtener un mejor manejo de esto debe provenir del punto de vista de 'capacidades' y no del punto de vista del código.

Usted, su empresa y su producto no pueden ser todo para todos. Ahora que tiene una base de ingresos decente de 500 clientes, es hora de productivizar en lo que pretende ser.

Y si ofrece varias cosas, tendría sentido modularizar las capacidades de su producto de manera organizada.

¿Qué tan amplios y profundos serán sus productos? O bien, esto conducirá a problemas de 'calidad de servicio' y 'dilución y fragmentación del producto' a medida que avance la línea.

¿ Serás un CRM o ERP o procesamiento / despacho de pedidos o Microsoft Excel?

Sus extensiones existentes deben acumularse y armonizarse, de la misma manera que un gran software atrae y fusiona productos adquiridos de una startup.

Necesitará contar con una sólida persona de administración de productos y arquitectura de datos que asigne lo siguiente:

  • Rama maestra, sus capacidades de producto y base de características
  • Características, tipos y variaciones de extensiones personalizadas
  • Importancia y variación de los "campos personalizados"

..para crear una hoja de ruta de asimilación y armonización de todos estos hilos / ramas de productos sueltos en el gran contexto de su aplicación principal.

PD: Conéctate conmigo, conozco a una persona que puede ayudarte a solucionar esto :)


-5

Me identifico con esto. He tomado muchos proyectos. De hecho, el 90% de nuestro trabajo de desarrollo está arreglando tales cosas. No todos son perfectos, por lo que te sugiero que uses el control de versiones de la manera correcta y dónde estás, si es posible, puedes hacer lo siguiente.

  • De ahora en adelante, cuando un cliente solicite una actualización, muévalo a un nuevo repositorio bifurcado.
  • Si desea fusionarlos para dominar, hágalo como lo primero y resuelva los conflictos.
  • Luego administre sus problemas y sprints con su repositorio y mantenga aquellos en master que desee iniciar en master. Esto podría ejercer más presión sobre los ciclos de liberación, pero eso le ahorrará con el tiempo.
  • Mantenga una rama maestra del repositorio principal para nuevos clientes y el repositorio principal solo debe tener esas ramas en las que está trabajando para cosas futuras. Las ramas heredadas se pueden eliminar una vez que se migran a los repositorios de los clientes.

Personalmente importé un repositorio de GitHub con 40 sucursales a Bitbucket y creé 40 repositorios. Solo tomó cuatro horas. Estas fueron las variaciones del tema de WordPress , así que empujar y tirar fue rápido.

Hay muchas razones para "no hacerlo bien la primera vez", y creo que aquellos que las aceptan rápidamente y continúan con "hacerlo bien esta vez" siempre tendrán éxito.


16
¿Cómo facilitarían los repositorios múltiples el mantenimiento?
Mathletics

En algunos casos como el nuestro, los clientes necesitan tener acceso a cada repositorio y administrar sus propios problemas cuando se convierte en una solución personalizada, por lo que tienen su propio repositorio, lo que hace que sea más fácil de administrar y, como dije, estas son variaciones de temas de WordPress, funcionó bien. Puede que no funcione en muchos casos.
Farrukh Subhani
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.