Mantener cientos de sucursales personalizadas sobre la rama maestra

138

Actualmente tenemos una rama maestra para nuestra aplicación PHP en un repositorio compartido. Tenemos más de 500 clientes que son suscriptores de nuestro software, la mayoría de los cuales tienen cierta 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 característica 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 proporcionamos una nueva característica y actualizamos nuestra sucursal maestra, y nos gustaría impulsar los cambios de la sucursal maestra a las sucursales personalizadas en Para actualizarlos a la última versión.

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

Estoy buscando una manera más eficiente de mantener las sucursales de lanzamiento de nuestros clientes al día con la rama maestra que resultará en un menor esfuerzo durante la fusión.

    
pregunta Fernando Tan 09.11.2015 - 17:00

9 respuestas

307

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

Por ejemplo, haga que las etiquetas de los campos de texto provengan de un archivo de texto, no se incluyan 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 gobernados por API estrictas y estables, de modo que las características se puedan insertar según sea necesario.

La infraestructura central, y cualquier característica compartida, solo necesitan ser almacenadas, mantenidas y probadas una vez .

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

    
respondido por el Lightness Races in Orbit 09.11.2015 - 17:03
91

Tener 500 clientes es un buen problema, si ha 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 le cobre a sus clientes lo suficiente para cubrir TODOS los costos de mantener sus versiones personalizadas. Estoy asumiendo 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 para poder 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 sola vez, solo haga configurable una etiqueta de campo de texto la primera vez que un cliente quiera cambiarla).

Luego continúe con 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 marque un archivo en una rama, DEBE difuminarlo 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.

Tu objetivo es pasar primero de 500 sucursales con muchos archivos diferentes, a la mayoría de las sucursales que solo tienen unos pocos archivos diferentes. Mientras ganas suficiente dinero para vivir.

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

Basado en el comentario de br3w5:

  • Podría tomar cada clase que sea diferente entre los clientes
  • Haz una "xxx_baseclass" que defina todos los métodos que se llaman 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 la inteligente idea 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 una vez que haya obtenido el grano fácil, y siga con unas pocas clases primero.

    
respondido por el Ian 09.11.2015 - 19:56
40

En el futuro, pregunte la prueba de Joel en su entrevista. Tendrías más probabilidades de no entrar en un tren de tren.

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

¿En qué medida están integrados estos cambios personalizados con el "núcleo"? ¿Puede crear su propia biblioteca y tener un único "núcleo" y cada cliente específico tiene su propio "complemento"?

¿O son todas estas configuraciones muy pequeñas?

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

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

Tampoco será trivial, ya que si terminaste aquí con más de 500 clientes, es probable que no hagas ninguna distinción real en esto. Espero que sus cambios en la separación de esta tarea lleven mucho tiempo.

También sospecho que va a tener problemas importantes para separar y categorizar 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 de idiomas. Ya sea que esté haciendo varios idiomas completamente o solo un subconjunto, la solución es la misma. Esto es específicamente PHP y localización.

    
respondido por el enderland 09.11.2015 - 17:13
17

Este es uno de los peores patrones que puedes golpear con cualquier VCS.

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

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

    
respondido por el Daenyth 09.11.2015 - 17:03
13

El propósito de las sucursales es explorar una posible vía de desarrollo sin el riesgo de romper la estabilidad de la rama principal. Eventualmente deben fusionarse en un momento adecuado, o descartarse si llevan a un callejón sin salida. Lo que tienes no son tanto sucursales, sino más bien 500 bifurcaciones del mismo proyecto y tratar de aplicar los conjuntos de cambios vitales a todos ellos es una tarea de Sisyphean.

En su lugar, 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 permitido por dependencias invertidas .

Las diferentes configuraciones que tiene para los clientes pueden simplemente distinguirse entre sí por algún 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.

    
respondido por el back2dos 09.11.2015 - 18:08
7

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

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

Lo que significa:

  1. Aclare las responsabilidades de administración de cambios: si un cliente necesita algunas adaptaciones, quién las está vendiendo, quién les está permitiendo y quién decide cómo ¿Se cambiará el código? ¿Dónde están los tornillos para girar si algunas cosas deben ser cambios?
  2. Clarifique el rol, who en su equipo puede hacer nuevos repositorios, y who no.
  3. Trate de 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é, algo de "lista de 500" suena molesto, pero aquí hay algo de "economía emocional", si lo desea. Si no puede ver los cambios del cliente en un tiempo rápido, se siente aún más perdido y dibujado 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
    • cambios relacionados con el grupo por tema
    • 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: grupo por cambios costosos y baratos .

Esto no significa en modo alguno crear una mala atmósfera de presión en su equipo. Prefiero sugerir que aclare estos puntos primero para usted y, donde quiera que sienta el apoyo, organice esto junto con su equipo. Invita a gente amigable a la mesa para mejorar toda tu experiencia.

Luego, trata de establecer una ventana de tiempo a largo plazo, donde cocines esto en una pequeña llama. Sugerencia: intente combinar al menos dos reposiciones por semana, y así eliminar al menos uno . Puede aprender que a menudo, puede combinar más de dos sucursales, a medida que obtiene la rutina y la supervisión. De esa manera, en un año puede ocuparse de las peores (¿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 el que no lo permitirá más, ya que usted es el arquitecto de 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 permite esto, cómo se le brinda soporte y también lo que aún tiene que aprender. Usted es el arquitecto de software. Simplemente inténtelo :-)

    
respondido por el peter_the_oak 10.11.2015 - 07:11
5

Contrastando a todos los nay-sayers, asumamos una verdadera necesidad comercial.

(por ejemplo, entregable es el código fuente, los clientes pertenecen a la misma línea de negocios y, por lo tanto, son 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 devs suponiendo retraso de publicación de 50 días está bien), o tales pruebas automáticas tan impresionantes que las fusiones automáticas se prueban realmente tanto con especificación básica como especificación de extensión en cada Rama, y por lo tanto, solo los cambios que no se fusionan "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 de negocio válido.

Mi pregunta (y ninguna respuesta) es: ¿tienes 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 puede ser manejado por arquitectura de complementos en algunos casos, digamos que su núcleo es troncal, los complementos podrían mantenerse en troncales o sucursales, y la configuración para cada cliente es un archivo con un nombre único o es celebrado en la sucursal del cliente.

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

En realidad, muchos proyectos se realizan de esta manera, fundamentalmente se aplica el mismo problema: los cambios básicos simples son triviales de 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, que es cuando se deben ajustar tantos elementos internos del núcleo que el recuento de la interfaz del complemento es demasiado grande para manejar.

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

En un ejemplo sencillo, puede especificar que se ejecute foo personalizado antes o después del núcleo klass.foo o que lo reemplace, o que lo 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: las fusiones limpias son manejadas por AOP y los conflictos aún necesitan la intervención humana.

Finalmente, este tipo de negocio realmente tiene que preocuparse por el mantenimiento de la sucursal , es decir, es una característica específica del cliente X tan común que es más económico pasarla al núcleo, aunque no todos los clientes la están pagando ?

    
respondido por el Dima Tisnek 10.11.2015 - 16:50
3

No está resolviendo la causa raíz de la enfermedad al observar el síntoma. El uso de un enfoque de 'administración de código' es sintomático, pero no solucionará los problemas a largo plazo. La causa principal es la falta de capacidades, características y funciones del producto 'bien administradas' Sus extensiones y variaciones.

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

Qué tan extensas son las características personalizadas, qué tan diferentes, qué tan similar o no al contexto jugará mucho en la "desinfección" de la base de código de su producto.

Más que cómo codificas y versiones, este es un lugar donde la gestión de productos, la arquitectura de productos y la arquitectura de datos entran en juego. En serio.

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

Obtener un mejor control de esto debe provenir del punto de vista de las '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 el momento de hacer un producto de lo que pretende ser.

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

¿Qué tan amplios y profundos serán sus productos? O, de lo contrario, esto dará lugar a problemas de "calidad de servicio" y a 'Dilución y fragmentación del producto' a medida que avanza por la línea.

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

Sus extensiones existentes deben enrollarse y armonizarse, de la forma en que una gran empresa de software incorpora y fusiona los productos adquiridos desde un inicio.

Necesitará tener un administrador de productos y una arquitectura de datos , mapear lo siguiente:

  • Rama maestra, sus capacidades de producto y base de características
  • Funciones, tipos y variaciones de extensiones personalizadas
  • Significado y variación de los 'campos personalizados'

..para crear un mapa 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 :)

    
respondido por el Alex S 10.11.2015 - 06:21
-5

Puedo relacionarme con esto. He tomado muchos proyectos en. De hecho, el 90% de nuestro trabajo de desarrollo es arreglar esas cosas. No todos son perfectos, por lo que te sugiero que utilices el control de versiones de la manera correcta y donde estés, si es posible, puedes hacer lo siguiente.

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

Personalmente he importado un repositorio de GitHub con 40 sucursales a Bitbucket y he creado 40 repositorios. Sólo tardó cuatro horas. Estas fueron las variaciones del tema WordPress , por lo 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 pasan a "hacerlo bien esta vez" siempre tendrían éxito.

    
respondido por el Farrukh Subhani 09.11.2015 - 22:01

Lea otras preguntas en las etiquetas