Actuellement, nous avons une branche principale pour notre application PHP dans un référentiel partagé. Nous avons plus de 500 clients abonnés à notre logiciel. La plupart d’entre eux peuvent être personnalisés à des fins différentes, chacun dans une branche distincte. La personnalisation peut être un nom de champ de texte différent, une fonctionnalité ou un module totalement nouveau, ou de nouvelles tables / colonnes dans la base de données.
Le défi auquel nous sommes confrontés est qu’au fur et à mesure que nous maintenons ces centaines de succursales personnalisées et les distribuons aux clients, nous fournissons de temps en temps de nouvelles fonctionnalités et mettons à jour notre branche principale. les à la dernière version.
Malheureusement, cela entraîne souvent de nombreux conflits dans le code personnalisé et nous passons de nombreuses heures à parcourir chaque branche pour résoudre tous les conflits. C'est très inefficace et nous avons constaté que les erreurs ne sont pas rares lors de la résolution de ces conflits.
Je recherche un moyen plus efficace de maintenir nos succursales de publication clientes à jour avec la succursale principale, ce qui nécessitera moins d'effort lors de la fusion.
la source
Réponses:
Vous abusez complètement des branches! La personnalisation doit être optimisée par la flexibilité de votre application, et non de la souplesse de votre contrôle de version (qui, comme vous l'avez découvert, n'est pas destiné / conçu pour ce type d'utilisation).
Par exemple, faites en sorte que les étiquettes de champs de texte proviennent d'un fichier texte et ne soient pas codées en dur dans votre application (c'est ainsi que fonctionne l'internationalisation). Si certains clients ont des fonctionnalités différentes, rendez votre application modulaire , avec des limites internes strictes régies par des API rigoureuses et stables, afin que les fonctionnalités puissent être connectées à la demande .
L'infrastructure de base et toutes les fonctionnalités partagées ne doivent alors être stockées, maintenues et testées qu'une seule fois .
Vous auriez dû le faire depuis le début. Si vous avez déjà cinq cents variantes de produit (!), Résoudre ce problème sera un travail énorme … mais pas plus que la maintenance en cours.
la source
Avoir 500 clients est un bon problème. Si vous aviez passé du temps à éviter ce problème avec les succursales, vous n’auriez peut-être jamais pu rester en affaires assez longtemps pour obtenir des clients.
Premièrement, j'espère que vous facturez vos clients suffisamment pour couvrir TOUS les coûts de maintenance de leurs versions personnalisées. Je suppose que les clients s'attendent à obtenir de nouvelles versions sans avoir à payer pour que leurs personnalisations soient répétées. Je commencerais par trouver tous les fichiers identiques dans 95% de vos succursales. Ce 95% est la partie stable de votre application.
Recherchez ensuite tous les fichiers ne contenant que quelques lignes différentes entre les branches. Essayez d’introduire un système de configuration tel que ces différences puissent être supprimées. Ainsi, par exemple, plutôt que d'avoir des centaines de fichiers avec des étiquettes de champs de texte différentes, vous disposez d'un fichier de configuration pouvant remplacer n'importe quelle étiquette de texte. (Cela ne doit pas nécessairement être fait en une fois, il suffit de configurer une étiquette de champ de texte configurable la première fois qu'un client veut le changer.)
Passez ensuite aux problèmes les plus difficiles en utilisant le modèle de stratégie, l’injection de dépendance, etc.
Envisagez de stocker json dans la base de données plutôt que d'ajouter des colonnes pour les propres champs du client. Cela peut fonctionner pour vous si vous n'avez pas besoin de rechercher ces champs avec SQL.
Chaque fois que vous archivez un fichier dans une branche, vous DEVEZ le différencier avec principal et justifier chaque modification, y compris les espaces. Beaucoup de changements ne seront pas nécessaires et peuvent être supprimés avant l'enregistrement. Cela peut simplement être dû à un développeur ayant différents paramètres dans son éditeur pour la façon dont le code est formaté.
Votre objectif est d’abord de passer de 500 branches contenant un grand nombre de fichiers différents à la plupart des branches n’ayant que quelques fichiers différents. Tout en gagnant assez d'argent pour vivre.
Vous pouvez toujours avoir 500 succursales dans de nombreuses années, mais si elles sont beaucoup plus faciles à gérer, alors vous avez gagné.
Basé sur le commentaire de br3w5:
Ne faites ce que ci-dessus après avoir obtenu le grain facile, et suivez-le d'abord avec quelques classes.
la source
À l'avenir, posez les questions du test Joel lors de votre entretien. Vous seriez plus susceptible de ne pas marcher dans une épave de train.
C'est un, ah, comment dirons-nous ... vraiment, vraiment grave problème à avoir. Le "taux d'intérêt" sur cette dette technique va être très très élevé. Ce n'est peut-être pas récupérable ...
Dans quelle mesure ces modifications personnalisées sont-elles intégrées au "noyau"? Pouvez-vous leur faire leur propre bibliothèque et avoir un seul "noyau" et chaque client spécifique ayant son propre "add-on"?
Ou s'agit-il de configurations très mineures?
Je pense que la solution est une combinaison de:
Ni l'un ni l'autre ne sera trivial comme si vous vous retrouviez ici avec plus de 500 clients, vous n'avez probablement pas fait de réelle distinction à cet égard. Je prévois que vos changements dans la séparation de cette tâche prendront beaucoup de temps.
Je soupçonne également que vous allez avoir de gros problèmes pour séparer et classer facilement tout votre code spécifique au client.
Si la plupart de vos modifications portent spécifiquement sur des différences de formulation, je suggère de lire des questions telles que celle-ci sur la localisation linguistique. Que vous fassiez plusieurs langues entièrement ou juste un sous-ensemble, la solution est la même. C'est spécifiquement PHP et la localisation.
la source
C’est l’un des pires anti-modèles que vous pouvez utiliser avec un VCS.
La bonne approche consiste à transformer le code personnalisé en un élément piloté par la configuration. Chaque client peut ensuite avoir sa propre configuration, codée en dur dans un fichier de configuration, dans une base de données ou à un autre emplacement. Vous pouvez activer ou désactiver des fonctionnalités complètes, personnaliser l'apparence des réponses, etc.
Cela vous permet de conserver une branche principale avec votre code de production.
la source
if(getFeature(FEATURE_X).isEnabled())
.Le but des branches est d’explorer une voie de développement possible sans risquer de casser la stabilité de la branche principale. Ils devraient finalement être fusionnés à un moment opportun ou être jetés s'ils mènent à une impasse. Ce que vous avez ne sont pas tellement des branches, mais bien plutôt 500 fourchettes du même projet et essayer d'appliquer les ensembles de modifications vitales à toutes est une tâche sisyphéenne.
Au lieu de cela, vous devez faire en sorte que votre code principal soit stocké dans son propre référentiel, avec les points d'entrée nécessaires pour modifier le comportement via la configuration et pour injecter le comportement autorisé par les dépendances inversées .
Les différentes configurations que vous avez pour les clients peuvent alors simplement se distinguer par certains états configurés de manière externe (par exemple, une base de données) ou si nécessaire vivre en tant que référentiels séparés, qui ajoutent le noyau en tant que sous-module.
la source
Toutes les choses importantes ont été proposées par de bonnes réponses ici. J'aimerais ajouter mes cinq sous comme une suggestion de processus.
J'aimerais vous suggérer de résoudre ce problème à moyen ou long terme et d'adopter votre politique, la manière dont vous développez le code. Essayez de devenir une équipe d'apprentissage flexible. Si quelqu'un a autorisé 500 repos au lieu de rendre le logiciel configurable, il est temps de se demander comment vous avez travaillé jusqu'à présent et vous le ferez à partir de maintenant.
Ce qui signifie:
Cela n’a aucunement pour but de créer une atmosphère de mauvaise pression dans votre équipe. Je suggère plutôt que vous clarifiiez d'abord ces points pour vous-même et, où que vous sentiez le soutien, organisez cela avec votre équipe. Invitez des personnes amicales à la table afin d’améliorer votre expérience.
Ensuite, essayez d’établir une fenêtre de temps à long terme, où vous cuisinez cette chose sur une petite flamme. Suggestion: essayez de fusionner au moins deux pensions chaque semaine et supprimez-en au moins un . Vous apprendrez peut-être que souvent, vous pouvez fusionner plus de deux branches à mesure que vous obtenez une routine et une surveillance. De cette façon, en un an, vous pourrez traiter les pires branches (les plus chères?) Et, en deux ans, vous pourrez réduire ce problème et obtenir un logiciel nettement meilleur. Mais ne vous attendez pas à plus, car à la fin, personne n’aura le temps de le faire, mais c’est vous qui ne le permettrez plus car vous êtes l’architecte du logiciel.
C'est comme cela que j'essaierais de le gérer si j'étais à votre place. Cependant, je ne sais pas comment votre équipe va accepter de telles choses, comment le logiciel le permet vraiment, comment vous êtes pris en charge et aussi ce que vous devez encore apprendre. Vous êtes l'architecte logiciel - allez-y :-)
la source
En comparant tous les opposants, supposons un réel besoin commercial.
(Par exemple, le livrable est un code source, les clients appartiennent au même secteur d’activité et sont donc concurrents, et votre modèle d’entreprise promet de garder le secret sur eux.)
De plus, supposons que votre société dispose des outils nécessaires pour gérer toutes les branches, c’est-à-dire soit de la main-d’œuvre (par exemple, 100 développeurs dédiés à la fusion, avec un délai de publication de 5 jours; ou 10 développeurs en supposant qu’un délai de publication de 50 jours est acceptable), ou de tels tests automatisés géniaux que les fusions automatisées sont réellement testées à la fois par rapport aux spécifications principales et aux spécifications d' extension dans chaque branche, et donc uniquement les modifications qui ne fusionnent pas "proprement" nécessitent une intervention humaine. Si vos clients paient non seulement pour des personnalisations, mais pour leur maintenance, il peut s’agir d’un modèle commercial valide.
Ma question (et non-dire) est: avez-vous une personne dédiée responsable de la livraison à chaque client? Si vous êtes, par exemple, une entreprise de 10 000 personnes, cela peut être le cas.
Cela peut être géré par l’ architecture de plug-in dans certains cas, disons que votre cœur est un trunk, que les plug-ins peuvent être conservés dans des trunk ou des branches, et que la configuration de chaque client est un fichier portant un nom unique ou est conservée dans une branche du client.
Les plugins peuvent être chargés au moment de l'exécution ou intégrés à la compilation.
Vraiment, de nombreux projets sont réalisés de la sorte, mais le problème est fondamentalement le même: des modifications de base simples sont faciles à intégrer, les modifications de conflit doivent être soit annulées, soit nécessaires pour de nombreux plug-ins.
Il y a des cas où les plugins ne sont pas assez bons, c'est-à-dire que de nombreux internes du noyau doivent être peaufinés, ce qui fait que le nombre d'interfaces de plugins devient trop important pour être géré.
Idéalement, cela serait géré par une programmation orientée aspect , où trunk est le code principal et les branches sont des aspects (c'est-à-dire du code supplémentaire et des instructions sur la manière de connecter des extras au noyau).
Un exemple simple, vous pouvez spécifier que personnalisé
foo
est exécuté avant ou après le noyau,klass.foo
qu'il le remplace ou qu'il l'enveloppe et qu'il peut modifier l'entrée ou la sortie.Il existe une tonne de bibliothèques pour cela, mais le problème des conflits de fusion ne disparaît pas - les fusions saines sont gérées par AOP et les conflits nécessitent toujours une intervention humaine.
Enfin, une telle activité doit réellement concerner la maintenance des succursales , à savoir: la fonctionnalité X spécifique au client est-elle si commune qu'il est moins coûteux de la transférer au cœur du système, même si tous les clients n'en paient pas le coût?
la source
Vous ne résolvez pas la cause première de la maladie en observant le symptôme. L'utilisation d'une approche de «gestion du code» est symptomatique, mais ne résoudra pas les problèmes pour vous à long terme. La cause fondamentale est le manque de fonctionnalités, de fonctionnalités et de leurs extensions et variantes du produit "bien géré".
Votre code "personnalisé" ne représente rien d'autre que des extensions des fonctionnalités du produit et des modifications apportées aux champs de données .
L’étendue des fonctionnalités personnalisées, leur différence, leur similarité contextuelle ou non joueront un rôle important dans la «désinfection» de la base de code de votre produit.
Plus que la manière dont vous codez et la version, c'est un endroit où la gestion de produit, l'architecture de produit et l'architecture de données entrent en jeu. Sérieusement.
En fin de compte, le code n’est rien d’autre que votre offre de fonctionnalités / services commerciaux et produits à vos clients. C'est pour cela que votre entreprise est payée.
Cela doit être mieux maîtrisé du point de vue des "capacités" que du code.
Vous, votre entreprise et votre produit ne pouvez pas être tout pour tout le monde. Maintenant que vous disposez d'une base de revenus décente de 500 clients, il est temps de vous concentrer sur ce que vous avez l'intention de devenir.
Et si vous proposez plusieurs solutions, il serait judicieux de modulariser les fonctionnalités de vos produits de manière organisée.
Quelle sera l'ampleur et la profondeur de vos produits? Sinon, cela entraînera des problèmes de «qualité de service» et de «dilution et fragmentation du produit» au fur et à mesure de votre progression.
Serez-vous un CRM ou un ERP ou un traitement / envoi de commande ou Microsoft Excel?
Vos extensions existantes doivent être consolidées et harmonisées, comme un grand éditeur logiciel qui intègre et fusionne les produits acquis dans une startup.
Vous devez disposer d'une personne de qualité chargée de la gestion des produits et de l'architecture des données :
..pour créer une feuille de route d'assimilation et d'harmonisation de tous ces fils / branches de produits en vrac dans le contexte général de votre application principale.
PS: Connectez-vous à moi, je connais une personne qui peut vous aider à résoudre ce problème :)
la source
Je peux comprendre cela. J'ai pris beaucoup de projets. En fait, 90% de notre travail de développement consiste à réparer de tels problèmes. Tout le monde n’est pas parfait, je vous suggère donc d’utiliser le contrôle de version correctement et à l’endroit où vous vous trouvez. Si possible, procédez comme suit.
J'ai personnellement importé un référentiel de GitHub avec 40 branches dans Bitbucket et créé 40 référentiels. Cela n'a pris que quatre heures. Cela a été WordPress variations thématiques poussent donc et tirer était rapide.
Il y a de nombreuses raisons pour "ne pas bien faire les choses du premier coup" et je pense que ceux qui les acceptent rapidement et passent à "faire les choses correctement cette fois" auront toujours du succès.
la source