Tous les articles

Monorepo ou multi-repo : pourquoi 5 dépôts séparés

7 min de lecture

Monorepo ou multi-repo : la question se pose dès qu'un projet se découpe en plusieurs services. Pour aider un joueur à comparer deux builds d'équipement, il m'a fallu des données de jeu propres, complètes et à jour, resynchronisées à chaque patch. Ce prérequis a donné cinq dépôts, et je les ai gardés séparés.

Ces cinq systèmes distincts n'ont ni le même langage, ni le même rythme, ni la même charge. Cet article raconte ce qui a tranché entre un monorepo et plusieurs dépôts, et ce que ce choix me coûte au quotidien.

Voici le pipeline en une vue, du client du jeu jusqu'au navigateur :

Client du jeu
binaire opaque
Décodeur
suit la dérive
Hub ETL
agrège, versionne
Web-app + rendu
Postgres, Rust
Navigateur
builds comparés
Un numéro de version se propage dans un seul sens, du jeu jusqu'au navigateur.

Chaque brique a son article dans la série ; la visite d'ensemble les présente une par une :

Ce que disent les comparatifs monorepo ou multi-repo

La plupart des comparatifs monorepo ou multi-repo sont écrits pour des équipes. Un monorepo regroupe le code de plusieurs projets dans un seul dépôt git : des modifications atomiques entre projets, des packages partagés, une seule copie de chaque dépendance, des outils de build qui connaissent tout le graphe. C'est l'approche des grandes entreprises, qui gèrent des monorepos à grande échelle avec un outillage dédié. Le multi-repo, ou polyrepo, donne à chaque équipe ses propres dépôts : des publications indépendantes, des droits séparés, moins de coordination, et le libre choix de ses outils de développement.

MonorepoPolyrepo
Modifications entre projetsun commit atomiqueune publication par dépôt, dans l'ordre
Dépendancesune seule copie pour tout le codechaque projet gère les siennes
Builddemande un outillage dédié (Nx, Turborepo, Bazel) pour passer à l'échelleun build par repo, simple mais répété
Droits d'accèsun seul dépôt, au mieux des règles par dossierdes droits par repo
Équipestoutes les équipes travaillent dans le même codechaque équipe publie de façon indépendante

Aucune des deux approches n'est meilleure en général. La bonne réponse dépend de ce que les projets partagent vraiment. Dans mon cas, la question n'était pas comment plusieurs équipes partagent du code, mais comment cinq projets qui n'ont rien en commun partagent des données.

Monorepo ou multi-repo : ce qui a tranché

La tentation, au départ, aurait été un monorepo : un seul dépôt git, un seul historique, après tout c'est le même projet. Mais mis côte à côte, ces cinq dépôts n'ont presque rien en commun :

DépôtLangageTourne quandProfil
DécodeurPythonà chaque patch du jeuponctuel
Hub ETLTypeScriptà chaque nouvel artefact publiépublie du JSON versionné et une base Postgres
Rendu de spritesRusten continuCPU intensif, peu de mémoire persistante
Web-appTypeScript (Next.js, AdonisJS)en continuutilisateurs en direct, Postgres et Redis
CDN d'imagesTypeScripten continuredimensionnement et cache, 90 lignes

Chaque projet a un rythme de changement, un langage et un profil de charge différents. Le décodeur ne tourne que lorsqu'un patch sort. Le rendu tourne en continu avec très peu de mémoire. La web-app a le rythme d'un produit avec des utilisateurs en direct. Les mettre dans un monorepo aurait couplé leurs cycles de vie, leurs builds et leurs déploiements sans raison. Les monorepos brillent quand plusieurs équipes partagent du code et des dépendances ; ici, le seul vrai lien entre les projets, ce sont des données.

Il y a aussi la question des accès. Le décodeur est le code le plus sensible du projet, la web-app accueille des contributeurs externes. En polyrepo, chaque repo a ses propres droits : un contributeur de la web-app ne voit jamais le code qui lit le client du jeu. Dans un monorepo, il faut reconstruire ce cloisonnement à la main, dossier par dossier.

Le contrat entre dépôts : une version à sens unique

Ce qui rend ces cinq dépôts cohérents, ce n'est pas un déploiement commun ni un langage partagé (il y a du Python, du Rust, du TypeScript, du SQL, et en face le Java décompilé du client), c'est un numéro de version qui se propage dans un seul sens.

Un patch sort, le décodeur produit des artefacts versionnés, le hub ETL publie son agrégat, le rendu et la web-app tirent chacun les artefacts qui les concernent, puis la base du produit est resynchronisée.

À aucun moment un dépôt en aval ne devine ou ne recalcule une donnée qu'un projet en amont aurait dû lui fournir déjà résolue. Chaque projet ne connaît de ses voisins que le format versionné qu'ils publient. Un monorepo aurait rendu cette règle facultative : avec tout le code au même endroit, rien n'empêche un projet d'aller piocher dans un autre.

Ce que le multi-repo coûte

Le polyrepo n'est pas gratuit. Le coût le plus concret : un changement qui traverse deux dépôts ne tient pas dans un seul commit. Si j'ajoute un champ dans le hub et que la web-app doit l'afficher, je publie d'abord une nouvelle version du hub, puis je mets à jour la web-app séparément. Dans un monorepo, ce serait une seule modification, une seule revue. Dans une équipe, ça demande aussi de coordonner des gens ; ici, c'est une question d'ordre de publication.

S'ajoute la maintenance multipliée par cinq : cinq configurations, cinq jeux de dépendances à suivre, cinq pipelines de build. Les monorepos règlent ça par le tooling : Nx ou Turborepo mutualisent la configuration de build et ne rebuildent que le code qui change.

Monorepo

Un changement transverse tient en une seule revue, l'outillage est partagé. Mais dans un monorepo, les cinq projets partagent aussi l'historique, les droits d'accès et la tentation d'importer directement le code d'un voisin.

Multi-repo (retenu)

Chaque dépôt garde son langage, son rythme et ses droits. Un changement transverse coûte deux publications, et l'interface entre projets reste un format versionné explicite.

Ce coût est le prix de la frontière explicite : pour toucher à deux dépôts, il faut passer par le format versionné qui les relie.

À retenir

Séparer ces dépôts a forcé une discipline utile : chaque frontière est une interface explicite, avec un format de données versionné, qu'on ne peut pas contourner en important discrètement une fonction interne d'un autre module.

Monorepo ou multi-repo en 4 points

  • Le multi-repo se justifie quand les projets diffèrent par le langage, le rythme de changement et le profil de charge ; un monorepo paie quand des équipes partagent du code.
  • Des dépôts séparés donnent des droits d'accès séparés, sans cloisonnement à reconstruire.
  • Le prix : un changement transverse se fait en deux temps, publier l'amont puis mettre à jour l'aval.
  • Le contrat entre dépôts est un format versionné qui ne circule que dans un sens, du patch vers le produit.

Cette discipline, appliquée à des données dont on ne maîtrise ni le format ni le rythme de changement, est le fil conducteur de tout le reste.

Réactions

Un clic sur une icône pour réagir.

Commentaires

Aucun commentaire · aucune réponse

Ajouter un commentaire

Aucune discussion pour le moment.
Soyez le premier à laisser un commentaire.

Secrets

0/20. Encore 20 à trouver.

Finissez un palier pour rendre clairs les indices du suivant.

Terminal