Il existe deux stratégies principales pour l’ hébergement et la gestion du code via Git : mono-repo vs multi-repo. Les deux approches ont leurs avantages et leurs inconvénients.

Nous pouvons utiliser l’une ou l’autre approche pour n’importe quelle base de code dans n’importe quelle langue. Vous pouvez utiliser n’importe laquelle de ces stratégies pour des projets contenant une poignée de bibliothèques à des milliers d’entre elles. Même si cela implique quelques membres de l’équipe ou des centaines, ou si vous souhaitez héberger du code privé ou open source, vous pouvez toujours opter pour le mono-repo ou le multi-repo en fonction de divers facteurs.

Quels sont les avantages et les inconvénients de chaque approche ? Quand doit-on utiliser l’une ou l’autre ? Découvrons-le !

Que sont les dépôts ?

Un dépôt (repository ou repo) est un stockage pour toutes les modifications et tous les fichiers d’un projet, permettant aux développeurs de « contrôler la version » des ressources du projet tout au long de sa phase de développement.

Nous nous référons généralement aux référentiels Git (tels que fournis par GitHub , GitLab ou Bitbucket ), mais le concept s’applique également à d’autres systèmes de contrôle de version (tels que Mercurial).

Qu’est-ce qu’un mono-repo ?

L’approche mon-orepo utilise un dépôt unique pour héberger tout le code des multiples bibliothèques ou services composant les projets d’une entreprise. À l’extrême, l’ensemble de la base de code d’une entreprise – couvrant divers projets et codé dans différentes langues – est hébergé dans un seul référentiel.

Avantages de mono-repo

L’hébergement de l’ensemble de la base de code sur un seul dépôt offre les avantages suivants.

Abaisse les barrières à l’entrée

Lorsque de nouveaux membres du personnel commencent à travailler pour une entreprise, ils doivent télécharger le code et installer les outils nécessaires pour commencer à travailler sur leurs tâches. Supposons que le projet soit dispersé dans de nombreux référentiels, chacun ayant ses instructions d’installation et l’outillage requis. Dans ce cas, la configuration initiale sera complexe et, le plus souvent, la documentation ne sera pas complète, obligeant ces nouveaux membres de l’équipe à demander de l’aide à leurs collègues.

Un mono-repo simplifie les choses. Comme il existe un seul emplacement contenant tout le code et la documentation, vous pouvez rationaliser la configuration initiale.

Gestion de code centralisée

Avoir un dépôt unique donne une visibilité de tout le code à tous les développeurs. Cela simplifie la gestion du code car nous pouvons utiliser un seul outil de suivi des problèmes pour surveiller tous les problèmes tout au long du cycle de vie de l’application.

Par exemple, ces caractéristiques sont précieuses lorsqu’un problème s’étend sur deux (ou plus) bibliothèques enfants avec le bogue existant sur la bibliothèque dépendante. Avec plusieurs dépôts, il peut être difficile de trouver le morceau de code où le problème se produit.

En plus de cela, nous aurions besoin de déterminer quel référentiel utiliser pour créer le problème, puis d’inviter et de signaler les membres d’autres équipes pour aider à résoudre le problème.

Avec un mono-repo, cependant, la localisation des problèmes de code et la collaboration pour le dépannage deviennent plus simples à réaliser.

Refactorisations indolore à l’échelle de l’application

Lors de la création d’une refactorisation du code à l’échelle de l’application, plusieurs bibliothèques seront affectées. Si vous les hébergez via plusieurs dépôts, la gestion de toutes les différentes demandes d’extraction (pull request) pour les maintenir synchronisées les unes avec les autres peut s’avérer être un défi.

Un mono-repo permet d’effectuer facilement toutes les modifications de tout le code pour toutes les bibliothèques et de le soumettre sous une seule pull request.

Plus difficile de casser la fonctionnalité adjacente

Avec le mono-repo, nous pouvons configurer tous les tests pour toutes les bibliothèques à exécuter chaque fois qu’une seule bibliothèque est modifiée. En conséquence, la probabilité de faire un changement dans certaines bibliothèques a minimisé les effets négatifs sur d’autres bibliothèques.

Les équipes partagent une culture de développement

Même si cela n’est pas impossible, avec une approche mono-repo, il devient difficile d’inspirer des sous-cultures uniques parmi différentes équipes. Puisqu’ils partageront le même dépôt, ils partageront très probablement les mêmes méthodologies de programmation et de gestion et utiliseront les mêmes outils de développement.

Problèmes avec l’approche mono-repo

L’utilisation d’un dépôt unique pour tout notre code présente plusieurs inconvénients.

Cycles de développement plus lents

Lorsque le code d’une bibliothèque contient des modifications avec rupture, qui font échouer les tests des bibliothèques dépendantes, le code doit également être corrigé avant de fusionner les modifications.

Si ces bibliothèques dépendent d’autres équipes, qui sont occupées à travailler sur une autre tâche et ne sont pas en mesure (ou ne veulent pas) d’adapter leur code pour éviter les changements de rupture et réussir les tests, le développement de la nouvelle fonctionnalité peut s’arrêter.

De plus, le projet pourrait bien ne commencer à avancer qu’à la vitesse de l’équipe la plus lente de l’entreprise. Ce résultat pourrait frustrer les membres des équipes les plus rapides, créant des conditions pour qu’ils veuillent quitter l’entreprise.

De plus, une bibliothèque devra également exécuter les tests pour toutes les autres bibliothèques. Les autres tests à exécuter, plus le temps qu’il faut pour les faire fonctionner, ce qui ralentit la façon dont nous pouvons rapidement itérer sur notre code.

Nécessite le téléchargement de la base de code entière

Lorsque le mono-repo contient tout le code d’une entreprise, il peut être énorme, contenant des gigaoctets de données. Pour contribuer à n’importe quelle bibliothèque hébergée à l’intérieur, n’importe qui aurait besoin d’un téléchargement de l’ensemble du référentiel.

Traiter avec une vaste base de code implique une mauvaise utilisation de l’espace sur nos disques durs et des interactions plus lentes avec celui-ci. Par exemple, les actions quotidiennes telles que l’exécution git status ou la recherche dans la base de code avec une expression régulière peuvent prendre plusieurs secondes voire plusieurs minutes de plus qu’avec plusieurs dépôts.

Les bibliothèques non modifiées peuvent avoir une nouvelle version

Lorsque nous balisons le mono-repo, tout le code est attribué au sein de la nouvelle balise. Si cette action déclenche une nouvelle version, alors toutes les bibliothèques hébergées dans le dépôt seront nouvellement publiées avec le numéro de version de la balise, même si nombre de ces bibliothèques n’ont subi aucun changement.

Le fork est plus difficile

Les projets open source doivent faciliter au maximum l’implication des contributeurs. Avec plusieurs dépôts, les contributeurs peuvent se diriger directement vers le dépôt spécifique du projet auquel ils souhaitent contribuer. Avec un mono-repo hébergeant divers projets, cependant, les contributeurs doivent d’abord se frayer un chemin dans le bon projet et devront comprendre comment leur contribution peut affecter tous les autres projets.

Qu’est-ce que le multi-repo ?

L’approche multi-repo utilise plusieurs dépôt pour héberger les multiples bibliothèques ou services d’un projet développé par une entreprise. À son extrême, il hébergera chaque ensemble minimum de code réutilisable ou de fonctionnalité autonome (telle qu’un micro-service) sous son dépôt.

Avantages du multi-repo

Héberger chaque bibliothèque indépendamment de toutes les autres offre une pléthore d’avantages.

Gestion des versions de bibliothèque indépendante

Lors du balisage d’un dépôt, l’ensemble de sa base de code se voit attribuer la « nouvelle » balise. Étant donné que seul le code d’une bibliothèque spécifique se trouve dans le dépôt, la bibliothèque peut être balisée et versionnée indépendamment de toutes les autres bibliothèques hébergées ailleurs.

Avoir une version indépendante pour chaque bibliothèque aide à définir l’arbre de dépendances de l’application, nous permettant de configurer la version de chaque bibliothèque à utiliser.

Versions de service indépendantes

Étant donné que le dépôt ne contient que le code d’un service et rien d’autre, il peut avoir son propre cycle de déploiement, indépendamment de tout progrès réalisé sur les applications qui y accèdent.

Le service peut utiliser un cycle de publication rapide tel que la livraison continue (où le nouveau code est déployé après avoir réussi tous les tests). Certaines bibliothèques accédant au service peuvent utiliser un cycle de publication plus lent, comme celles qui ne produisent une nouvelle version qu’une fois par semaine.

Aide à définir le contrôle d’accès dans toute l’organisation

Seuls les membres de l’équipe impliqués dans le développement d’une bibliothèque doivent être ajoutés au dépôt correspondant et télécharger son code. Par conséquent, il existe une stratégie de contrôle d’accès implicite pour chaque couche de l’application . Les personnes impliquées dans la bibliothèque se verront accorder des droits d’édition, et tout le monde n’aura peut-être pas accès au dépôt. Ou ils peuvent recevoir des droits de lecture mais pas d’édition.

Permet aux équipes de travailler de manière autonome

Les membres de l’équipe peuvent concevoir l’architecture de la bibliothèque et implémenter son code en travaillant indépendamment de toutes les autres équipes. Ils peuvent prendre des décisions en fonction de ce que fait la bibliothèque dans le contexte général sans être affectés par les exigences spécifiques d’une équipe ou d’une application externe.

Problèmes avec l’approche multi-repo

L’utilisation de plusieurs dépôt peut entraîner plusieurs problèmes.

Les bibliothèques doivent être constamment resynchronisées

Lorsqu’une nouvelle version d’une bibliothèque contenant des modifications de rupture est publiée, les bibliothèques dépendant de cette bibliothèque devront être adaptées pour commencer à utiliser la dernière version. Si le cycle de publication de la bibliothèque est plus rapide que celui de ses bibliothèques dépendantes, elles pourraient rapidement se désynchroniser les unes avec les autres.

Les équipes devront constamment se mettre à jour pour utiliser les dernières versions des autres équipes. Étant donné que différentes équipes ont des priorités différentes, cela peut parfois s’avérer difficile à réaliser.

Par conséquent, une équipe incapable de rattraper son retard peut finir par s’en tenir à la version obsolète de la bibliothèque dont elle dépend. Ce résultat aura des implications sur l’application (en termes de sécurité, de vitesse et d’autres considérations), et l’écart de développement entre les bibliothèques pourrait ne faire que s’élargir.

Peut fragmenter les équipes

Lorsque différentes équipes n’ont pas besoin d’interagir, elles peuvent travailler dans leurs propres silos. À long terme, cela pourrait amener les équipes à produire leurs sous-cultures au sein de l’entreprise, par exemple en utilisant différentes méthodologies de programmation ou de gestion ou en utilisant différents ensembles d’outils de développement.

Si un membre de l’équipe doit éventuellement travailler dans une autre équipe, il peut subir un choc culturel et apprendre une nouvelle façon de faire son travail.

Mono-repo vs multi-Repo : principales différences

Les deux approches traitent finalement du même objectif : la gestion de la base de code. Par conséquent, ils doivent tous les deux résoudre les mêmes défis, notamment la gestion des versions, la promotion de la collaboration entre les membres de l’équipe, la gestion des problèmes, l’exécution de tests, etc.

Leur principale différence concerne le timing des membres de l’équipe pour prendre des décisions : soit en amont pour le mono-repo, soit en aval pour le multi-repo.

Analysons cette idée plus en détail.

Étant donné que toutes les bibliothèques sont versionnées indépendamment dans le multi-repo, une équipe qui publie une bibliothèque avec des modifications importantes peut le faire en toute sécurité en attribuant un nouveau numéro de version majeure à la dernière version. D’autres groupes peuvent faire en sorte que leurs bibliothèques dépendantes s’en tiennent à l’ancienne version et passent à la nouvelle une fois leur code adapté.

Cette approche laisse la décision d’adapter toutes les autres bibliothèques à chaque équipe responsable, qui peut le faire à tout moment. Si elles le font trop tard et que de nouvelles versions de bibliothèques sont publiées, il deviendra de plus en plus difficile de combler le fossé entre les bibliothèques.

Par conséquent, alors qu’une équipe peut itérer rapidement et souvent sur son code, d’autres équipes peuvent s’avérer incapables de rattraper leur retard, produisant finalement des bibliothèques qui divergent.

D’un autre côté, dans un environnement mono-repo, nous ne pouvons pas publier une nouvelle version d’une bibliothèque qui casse une autre bibliothèque car leurs tests échoueront. Dans ce cas, la première équipe doit communiquer avec la deuxième équipe pour intégrer les changements.

Cette approche oblige les équipes à adapter complètement toutes les bibliothèques chaque fois qu’un changement doit se produire pour une seule bibliothèque. Toutes les équipes sont obligées de se parler et de trouver une solution ensemble.

En conséquence, la première équipe ne pourra pas itérer aussi vite qu’elle le souhaite, mais le code entre les différentes bibliothèques ne commencera à aucun moment à diverger.

En résumé, l’approche multi-repo peut aider à créer une culture de « aller vite et de casser les choses » parmi les équipes, où des équipes indépendantes agiles peuvent produire leur sortie à leur vitesse. Au lieu de cela, l’approche mono-repo favorise une culture de sensibilisation et d’attention, où les équipes ne doivent pas être laissées pour compte pour faire face à un problème toutes seules.

Approche hybride poly-as-mono

Si nous ne pouvons pas décider s’il faut utiliser les approches multi-repo ou mono-repo, il y a aussi l’approche intermédiaire : utiliser plusieurs dépôts et employer un outil pour les maintenir synchronisés, le faisant ressembler à un mono-repo mais avec plus de flexibilité.

Meta est l’un de ces outils. Il organise plusieurs dépôts sous des sous-répertoires et fournit une interface de ligne de commande qui exécute la même commande sur tous simultanément.

Un méta-repo contient les informations sur les dépôts qui composent un projet. Le clonage de ce dépôt via méta clonera ensuite de manière récursive tous les dépôts nécessaires, ce qui permettra aux nouveaux membres de l’équipe de commencer plus facilement à travailler sur leurs projets immédiatement.

Pour cloner un méta-repo et tous ses dépôts multiples définis, nous devons exécuter les opérations suivantes :

meta git clone [meta repo url]

Meta exécutera un git clone pour chaque dépôt et le placera dans un sous-répertoire :

Clonage d'un méta-projet.
Clonage d’un méta-projet. (Source de l’image : github.com/mateodelnorte/meta)

A partir de là, l’exécution de la meta exec commande exécutera la commande sur chaque sous-répertoire. Par exemple, l’exécution degit checkout master sur chaque dépôt se fait comme ceci :

meta exec "git checkout master"

Approche hybride mono-as-poly

Une autre approche consiste à gérer le code via un mono-repo pour le développement, mais en copiant le code de chaque bibliothèque dans son dépôt indépendant pour le déploiement.

Cette stratégie est répandue dans l’écosystème PHP car Packagist (le dépôt principal de Composer ) nécessite une URL de dépôt public pour publier un package, et il n’est pas possible d’indiquer que le package se trouve dans un sous-répertoire du dépôt.

Compte tenu de la limitation de Packagist, les projets PHP peuvent toujours utiliser un mono-repo pour le développement, mais ils doivent utiliser l’approche multi-repo pour le déploiement.

Pour réaliser cette conversion, nous pouvons exécuter un script avec git subtree split Ou utiliser l’un des outils disponibles qui exécutent la même logique :

Qui utilise mono-repo vs multi-repo

Plusieurs grandes entreprises technologiques privilégient l’approche mono-repo, tandis que d’autres ont décidé d’utiliser la méthode multi-repo.

Google, Facebook, Twitter et Uber se sont tous publiquement portés garants de l’approche mono-repo. Microsoft exécute le plus grand mono-repo Git de la planète  pour héberger le code source du système d’exploitation Windows.

De l’autre côté, Netflix, Amazon et Lyft sont des sociétés célèbres utilisant l’approche multi-repo.

Du côté hybride poly-as-mono, Android met à jour plusieurs dépôts, qui sont gérés comme un mono-repo.

Du côté hybride mono-as-poly, Symfony conserve le code de tous ses composants dans un mono-repo. Ils le divisent en dépôts indépendants pour le déploiement (tels que symfony/dependency-injection et symfony/event-dispatcher.)

Exemples de mono-repo et multi-repo

Le compte WordPress sur GitHub héberge des exemples des approches mono-repo et multi-repo.

Gutenberg , l’éditeur de blocs WordPress, est composé de plusieurs dizaines de packages JavaScript. Ces packages sont tous hébergés sur le mono-repo WordPress/gutenberg et gérés via Lerna pour faciliter leur publication dans le dépôt npm.

Openverse, le moteur de recherche de médias sous licence ouverte, héberge ses principales parties dans des dépôts indépendants : Front-end, Catalog et API.

Mono-repo vs multi-repo : comment choisir ?

Comme pour de nombreux problèmes de développement, il n’y a pas de réponse prédéfinie sur l’approche à utiliser. Différentes entreprises et projets bénéficieront d’une stratégie ou d’une autre en fonction de leurs conditions uniques, telles que :

  • Quelle est la taille de la base de code ? Contient-il des gigaoctets de données ?
  • Combien de personnes travailleront sur la base de code ? Est-ce environ 10, 100 ou 1 000 ?
  • Combien y aura-t-il de paquets ? Est-ce environ 10, 100 ou 1 000 ?
  • Sur combien de paquets l’équipe doit-elle travailler à un moment donné ?
  • Dans quelle mesure les paquets sont-ils étroitement liés ?
  • Différents langages de programmation sont-ils impliqués ? Nécessitent-ils l’ installation d’ un logiciel particulier ou d’un matériel spécial pour fonctionner ?
  • Combien d’outils de déploiement sont nécessaires et quelle est leur complexité à mettre en place ?
  • Quelle est la culture dans l’entreprise ? Les équipes sont-elles encouragées à collaborer ?
  • Quels outils et technologies les équipes savent-elles utiliser ?

Sommaire

Il existe deux stratégies principales pour l’hébergement et la gestion du code : mono-repo ou multi-repo. L’approche mono-repo consiste à stocker le code de différentes bibliothèques ou projets – et même tout le code d’une entreprise – dans un seul dépôt. Et le système multi-repo divise le code en unités, telles que des bibliothèques ou des services, et conserve leur code hébergé dans des dépôt indépendants.

Vous avez des questions sur mono-repo ou multi-repo ? Faites le nous savoir dans la section des commentaires !

Leonardo Losoviz

Leo writes about innovative web development trends, mostly concerning PHP, WordPress and GraphQL. You can find him at leoloso.com and twitter.com/losoviz.