Dans un environnement git
, où nous avons modularisé la plupart des projets, nous sommes confrontés au un projet par référentiel ou plusieurs projets par référentiel problème de conception. Prenons un projet modulaire:
myProject/
+-- gui
+-- core
+-- api
+-- implA
+-- implB
Aujourd'hui, nous avons un projet par référentiel . Il donne la liberté
release
composants individuelstag
composants individuelsMais il est également compliqué de branch
composants aussi souvent que la ramification api
nécessite des branches équivalentes dans core
, et peut-être d'autres composants.
Étant donné que nous voulons release
des composants individuels, pouvons-nous toujours obtenir la même flexibilité en utilisant une plusieurs projets par conception de référentiel .
Quelles sont les expériences et comment/pourquoi avez-vous abordé ces problèmes?
Il y a trois inconvénients majeurs à one project per repository
, comme vous l'avez décrit ci-dessus. Celles-ci sont moins vraies s'il s'agit de projets vraiment distincts, mais à en juger par les changements, il faut souvent des changements à un autre, ce qui peut vraiment exagérer ces problèmes:
git bisect
devient beaucoup plus difficile à utiliser lorsque vous fractionnez votre référentiel en sous-référentiels. C'est possible, ce n'est pas aussi facile, ce qui signifie que la chasse aux insectes en temps de crise est beaucoup plus difficile.git log
il suffit de ne pas afficher l'historique de manière aussi significative avec des structures de référentiel fracturées. Vous pouvez obtenir certaines sorties utiles avec des sous-modules ou des sous-arbres, ou par le biais d'autres méthodes scriptables, mais ce n'est pas la même chose que de taper tig --grep=<caseID>
ou git log --grep=<caseID>
et en analysant tous les commits qui vous intéressent. Votre histoire devient plus difficile à comprendre, ce qui la rend moins utile lorsque vous en avez vraiment besoin.En fin de compte, c'est un calcul du coût d'opportunité. Chez un ancien employeur, notre application principale était divisée en 35 sous-répertoires différents. De plus, nous avons utilisé un ensemble compliqué de scripts pour rechercher l'historique, nous assurer que l'état (c.-à-d. Les branches de production et de développement) était le même à travers eux, et les déployer individuellement ou en masse.
C'était trop; trop pour nous au moins. Les frais généraux de gestion ont rendu nos fonctionnalités moins agiles, rendu les déploiements beaucoup plus difficiles, rendu trop long l'enseignement des nouveaux développeurs, et à la fin de celui-ci, nous pouvions à peine nous rappeler pourquoi nous avons fracturé le référentiel en premier lieu. Un beau jour de printemps, j'ai dépensé 10 $ pour un après-midi de temps de calcul de cluster en EC2. J'ai remonté les dépôts avec quelques dizaines git filter-branch
appels. Nous n'avons jamais regardé en arrière.
Christopher a fait un très bon travail d'énumération des inconvénients d'un modèle à un projet par référentiel. Je voudrais discuter de certaines des raisons pour lesquelles vous pourriez envisager une approche à référentiels multiples. Dans de nombreux environnements dans lesquels j'ai travaillé, une approche multi-référentiels a été une solution raisonnable, mais la décision du nombre de référentiels à avoir, et où faire les coupes n'a pas toujours été facile à faire.
Dans mon poste actuel, j'ai migré un référentiel CVS géant à référentiel unique avec plus de dix ans d'histoire dans un certain nombre de référentiels git. Depuis cette décision initiale, le nombre de référentiels a augmenté (grâce aux actions d'autres équipes), au point où je pense que nous en avons plus que ce qui serait optimal. Certains nouveaux employés ont suggéré de fusionner les référentiels, mais je me suis opposé à cela. Le projet Wayland a une expérience similaire. Dans un entretien que j'ai vu récemment, ils avaient, à un moment donné, plus de 200 dépôts git, pour lesquels le responsable s'est excusé. En regardant leur site Web , je vois maintenant qu'ils sont à 5, ce qui semble raisonnable. Il est important de noter que la jonction et la division de référentiels est une tâche gérable, et il est normal d'expérimenter (dans des limites raisonnables).
Alors, quand pourriez-vous vouloir plusieurs référentiels?
Les points 2 et 3 ne sont significatifs que si le point 1 tient. En fractionnant nos référentiels, j'ai considérablement réduit les retards subis par nos collègues hors site, réduit la consommation de disque et amélioré le trafic réseau.
4 et 5 sont plus subtils. Lorsque vous divisez le référentiel d'un client et d'un serveur, cela rend plus coûteuse la coordination des modifications entre le code client et le code serveur. Cela peut être positif, car cela encourage une interface découplée entre les deux.
Même avec les inconvénients des projets multi-référentiels, beaucoup de travail respectable est fait de cette façon - Wayland et boost viennent à l'esprit. Je ne crois pas qu'un consensus sur les meilleures pratiques ait encore évolué, et un certain jugement est nécessaire. Des outils pour travailler avec plusieurs référentiels (git-subtree, git-submodule et autres) sont toujours en cours de développement et d'expérimentation. Mon conseil est d'expérimenter et d'être pragmatique.
Comme nous utilisons GitHub, nous avons en fait plusieurs projets dans un référentiel mais assurez-vous que ces projets/modules sont correctement modularisés (nous utilisons les conventions -api et -core + Maven + la vérification statique et d'exécution et pourraient même aller à OSGi un jour pour démarrer).
Sur quoi économise-t-il? Eh bien, nous n'avons pas à émettre plusieurs demandes d'extraction si nous modifions quelque chose de petit sur plusieurs projets. Les problèmes et le wiki sont centralisés, etc.
Nous traitons toujours chaque module/projet comme un projet indépendant approprié et les construisons et les intégrons séparément dans notre serveur CI, etc.
Pour moi, la principale différence dans l'utilisation d'un ou plusieurs référentiels réside dans les réponses aux questions suivantes:
À titre d'exemple, j'ai une petite application (client uniquement), qui vérifie la "qualité" d'un référentiel Subversion. Il y a l'implémentation de base, qui pourrait être démarrée à partir de la ligne de commande, et fonctionne bien avec Java 6. Mais j'ai commencé à implémenter une interface utilisateur, qui utilise JavaFX dans le cadre de Java 8. J'ai donc divisé les 2 et créé un deuxième référentiel (avec un deuxième processus de construction), avec un calendrier différent, ...
J'aime les réponses ci-dessus (les a votées), mais je pense qu'elles ne sont pas toute l'histoire vraie. Je voulais donc également ajouter les arguments pour fractionner les référentiels. Donc la vraie réponse (quand se séparer) peut être quelque part au milieu ...
Il se pourrait que git-subtree (voir blog Atlassian , blog moyen , ou lien noya ) serait un bon ajustement pour ce que vous avez. Ainsi, chacun de vos projets de niveau supérieur utiliserait un ensemble de sous-arborescences dans des versions éventuellement différentes.
D'après votre exemple, les référentiels doivent être configurés en fonction de leur interdépendance. Tout le raisonnement sur la conception de MicroServices et de Domain Driven Design s'applique ici: dans certains cas, le code en double est acceptable, travaillez avec des interfaces, ne brisez pas la compatibilité à moins que vous ne l'ayez vraiment, etc.
Maintenant, à mon avis, une interface utilisateur devrait être indépendante du backend. Un référentiel de projet d'interface utilisateur doit donc généralement contenir le code d'interface utilisateur et le contrôleur client. Le contrôleur client se connectera aux contrôleurs de service de manière abstraite. Ils utiliseront une abstraction client/api de service qui est versionnée séparément du service, afin qu'un service puisse être mis à jour sans casser le (s) client (s) (il peut y avoir plusieurs clients différents).
Un service lui-même doit donc être son propre référentiel. À mon avis, le service n'est qu'une enveloppe d'une logique métier à point de vérité unique. Par conséquent, la logique métier doit généralement être distincte de la technologie de service qui l'héberge. D'un autre côté, l'implémentation du référentiel est généralement si étroitement liée à la logique métier, qu'elle pourrait être intégrée dans le même référentiel. Mais même là, votre kilométrage peut varier.
Bien sûr, les projets simples qui ne changeront probablement pas beaucoup en termes de technologie ou de prise en charge de plusieurs piles, où toutes les interfaces utilisateur peuvent être hébergées à partir de la même source que le backend et les services backend ne sont généralement utilisés que par ce même client, peuvent bénéficier de plus des référentiels étroitement intégrés.
Dans ce cas, vous seriez probablement d'accord avec le simple fait d'avoir la verticale complète dans un référentiel, et de vous concentrer uniquement sur le fait que vos domaines fonctionnels sont correctement autonomes dans leur propre référentiel. Vous avez alors toujours la plupart des avantages des référentiels plus petits et peu de frais généraux sinon.