Démystification des Monorepos : Guide Complet. Partie 1 : Découverte et Comparaison des Outils

AL MOUSTAPHA DOUMBIA
data354
Published in
8 min readDec 12, 2023

Les monorepos, abréviation de référentiels monolithiques, ont gagné une popularité significative, notamment dans la communauté du développement web. Dans ce guide complet, nous explorerons les concepts fondamentaux des monorepos, pourquoi ils sont préférés, et les fonctionnalités essentielles qui en font une approche de développement puissante. Nous nous pencherons également sur les outils clés conçus pour optimiser les flux de travail monorepo, en mettant particulièrement l’accent sur Turborepo.

Qu’est-ce qu’un Monorepo ?

Un monorepo, ou référentiel monolithique, est un seul référentiel qui contient plusieurs projets distincts, chacun avec des relations bien définies. Contrairement à l’approche polyrepo traditionnelle, où chaque projet ou équipe a son propre référentiel, un monorepo consolide les projets sous un système de contrôle de version unifié.

Contrairement à la notion erronée selon laquelle les monorepos sont synonymes d’architectures monolithiques, un monorepo bien structuré n’implique pas une base de code monolithique. Il met l’accent sur l’idée de consolider des projets avec des dépendances et des relations claires.

Pourquoi Choisir un Monorepo ?

Le Problème du Polyrepo

Dans l’approche polyrepo conventionnelle, où chaque projet réside dans son propre référentiel, les équipes bénéficient de l’autonomie mais sont confrontées à des défis en matière de collaboration :

- Partage de Code Laborieux : Le partage de code entre les référentiels nécessite la configuration d’outils, d’environnements CI et la gestion des dépendances, entraînant une complexité accrue.

- Duplication Importante de Code : Les équipes dupliquent souvent des services et des composants communs entre les référentiels, entraînant des défis de maintenance et des problèmes de sécurité potentiels.

- Changements Coûteux entre les Référentiels : Traiter des bogues critiques ou des changements majeurs sur plusieurs référentiels avec des historiques de révision déconnectés devient un cauchemar de coordination.

- Outils Incohérents : Chaque projet peut utiliser un ensemble unique de commandes pour diverses tâches, entraînant une surcharge mentale et un manque de normalisation.

Avantages du Monorepo

Un monorepo adresse ces défis avec plusieurs avantages clés :

- Aucun Surcoût pour les Nouveaux Projets : La création de nouveaux projets dans un monorepo tire parti des configurations CI existantes, éliminant la nécessité de publier des packages versionnés lorsque les consommateurs sont dans le même référentiel.

- Commits Atomiques à Travers les Projets : Les modifications à travers les projets sont validées de manière atomique, évitant le risque de changements cassants lors de la résolution de problèmes ou de l’introduction de nouvelles fonctionnalités.

- Une Version de Tout : Les préoccupations d’incompatibilité dues à des versions conflictuelles de bibliothèques tierces sont éliminées, car tous les projets partagent la même version.

- Mobilité des Développeurs : Les développeurs peuvent contribuer en toute confiance aux applications de différentes équipes, garantissant que les modifications sont sûres et compatibles.

Fonctionnalités d’un Monorepo

Pour exploiter pleinement les avantages d’un monorepo, un ensemble de fonctionnalités clés est essentiel :

  1. Mise en Cache des Calculs Locaux : Mise en cache rapide des sorties de fichiers et de processus locaux pour éviter les constructions et les tests redondants.
processus de mise en cache des calculs locaux

2. Orchestration Locale des Tâches : Exécution des tâches dans le bon ordre et en parallèle localement.

exécution parallèle des tâches

3. Mise en Cache des Calculs Distribués : Partage d’artefacts mis en cache dans différents environnements pour éviter les constructions et les tests redondants à l’échelle de l’organisation.

processus de mise en cache des calculs distribués

4. Exécution Distribuée des Tâches : Distribution des tâches sur plusieurs machines tout en préservant l’expérience du développeur.

5. Exécution Transparente à Distance : Exécution de commandes sur plusieurs machines tout en développant localement.

6. Détection des Projets/Paquets Affectés : Détermination de l’impact des changements pour n’exécuter que les tâches de construction et de test nécessaires.

7. Analyse de l’Espace de Travail : Compréhension du graphe de projet de l’espace de travail sans configuration supplémentaire.

8. Visualisation du Graphe de Dépendances : Visualisation des relations de dépendance entre les projets et/ou les tâches.

un exemple de visualisation du graphe de dependances avec NX

9. Partage de Code Source : Facilitation du partage de morceaux discrets de code source.

partage de code source

10. Outils Cohérents : Offrir une expérience cohérente entre différentes technologies et frameworks.

11. Génération de Code : Support natif de la génération de code au sein du monorepo.

12. Contraintes et Visibilité du Projet : Définition de règles pour contraindre les relations de dépendance au sein du référentiel et gestion de la visibilité du projet.

Comparaison des Outils Monorepo

Bazel

  • Mise en cache des calculs locaux : Prise en charge
  • Orchestration locale des tâches : Prise en charge.
  • Mise en cache des calculs distribués : Prise en charge.
  • Exécution de tâches distribuées : Prise en charge (implémentation sophistiquée).
  • Exécution transparente à distance : Prise en charge.
  • Détection des projets/paquets affectés : Nécessite des outils tiers.
  • Analyse de l’espace de travail : Nécessite la rédaction manuelle des fichiers BUILD.
  • Visualisation du graphe de dépendances : Prise en charge.
  • Partage de code source : Prise en charge.
  • Outils cohérents : Extensible via des règles de construction.
  • Génération de code : Prise en charge des générateurs externes.
  • Contraintes et visibilité du projet : Prise en charge des règles de visibilité.

Gradle

  • Mise en cache des calculs locaux : Prise en charge.
  • Orchestration locale des tâches : Prise en charge.
  • Mise en cache des calculs distribués : Prise en charge.
  • Exécution de tâches distribuées : Prise en charge limitée.
  • Exécution transparente à distance : Non prise en charge.
  • Détection des projets/paquets affectés : Prise en charge.
  • Analyse de l’espace de travail : Prise en charge.
  • Visualisation du graphe de dépendances : Outils tiers disponibles.
  • Partage de code source : Prise en charge.
  • Outils cohérents : Extensible via des plugins.
  • Génération de code : Prise en charge des générateurs externes.
  • Contraintes et visibilité du projet : Possible avec le développement de plugins.

Lage

  • Mise en cache des calculs locaux : Prise en charge.
  • Orchestration locale des tâches : Prise en charge.
  • Mise en cache des calculs distribués : Prise en charge.
  • Exécution de tâches distribuées : Non prise en charge.
  • Exécution transparente à distance : Non prise en charge.
  • Détection des projets/paquets affectés : Prise en charge.
  • Analyse de l’espace de travail : Analyse des fichiers package.json.
  • Visualisation du graphe de dépendances : Non prise en charge.
  • Partage de code source : Prise en charge (uniquement pour les paquets npm).
  • Outils cohérents : Limité aux scripts npm.
  • Génération de code : Prise en charge des générateurs externes.
  • Contraintes et visibilité du projet : Contraintes basées sur le linter.

Lerna

  • Mise en cache des calculs locaux : Prise en charge.
  • Orchestration locale des tâches : Prise en charge.
  • Mise en cache des calculs distribués : Prise en charge (via Nx Cloud).
  • Exécution de tâches distribuées : Prise en charge (via Nx Cloud).
  • Exécution transparente à distance : Non prise en charge.
  • Détection des projets/paquets affectés : Prise en charge.
  • Analyse de l’espace de travail : Analyse des fichiers package.json.
  • Visualisation du graphe de dépendances : Non prise en charge.
  • Partage de code source : Prise en charge (uniquement pour les paquets npm).
  • Outils cohérents : Limité aux scripts npm.
  • Génération de code : Prise en charge des générateurs externes.
  • Contraintes et visibilité du projet : Contraintes basées sur le linter.

moon

  • Mise en cache des calculs locaux : Prise en charge.
  • Orchestration locale des tâches : Prise en charge.
  • Mise en cache des calculs distribués : Prise en charge.
  • Exécution de tâches distribuées : Non prise en charge.
  • Exécution transparente à distance : Non prise en charge.
  • Détection des projets/paquets affectés : Prise en charge.
  • Analyse de l’espace de travail : Analyse des fichiers manifest (package.json).
  • Visualisation du graphe de dépendances : Prise en charge de la visualisation interactive.
  • Partage de code source : Prise en charge (langages limités).
  • Outils cohérents : Peut exécuter n’importe quelle commande/binaire sur la machine.
  • Génération de code : Prise en charge de la génération de code basée sur le système de fichiers/les modèles.
  • Contraintes et visibilité du projet : Prise en charge intégrée des limites du projet.

Nx

  • Mise en cache des calculs locaux : Prise en charge (différenciation d’arbre pour la vitesse).
  • Orchestration locale des tâches : Prise en charge.
  • Mise en cache des calculs distribués : Prise en charge.
  • Exécution de tâches distribuées : Prise en charge.
  • Exécution transparente à distance : Non prise en charge.
  • Détection des projets/paquets affectés : Prise en charge.
  • Analyse de l’espace de travail : Analyse des fichiers package.json, JavaScript et TypeScript.
  • Visualisation du graphe de dépendances : Prise en charge.
  • Partage de code source : Prise en charge.
  • Outils cohérents : Fournit des commandes cohérentes et un système de plugins.
  • Génération de code : Prise en charge d’Angular CLI et de schematics.
  • Contraintes et visibilité du projet : Prise en charge via des contraintes architecturales.

Turborepo

  • Mise en cache des calculs locaux : Prise en charge.
  • Orchestration locale des tâches : Prise en charge.
  • Mise en cache des calculs distribués : Prise en charge.
  • Exécution de tâches distribuées : Prise en charge.
  • Exécution transparente à distance : Prise en charge.
  • Détection des projets/paquets affectés : Prise en charge.
  • Analyse de l’espace de travail : Analyse des fichiers package.json et des fichiers de code.
  • Visualisation du graphe de dépendances : Prise en charge.
  • Partage de code source : Prise en charge (niveau monorepo ou paquet).
  • Outils cohérents : Fournit des commandes cohérentes et prend en charge les scripts personnalisés.
  • Génération de code : Prise en charge des générateurs personnalisés.
  • Contraintes et visibilité du projet : Prise

Conclusion

Le choix de l’outil idéal pour votre monorepo dépend de divers facteurs, notamment la taille et la nature de vos projets, les préférences de votre équipe et des exigences spécifiques. Bien que Bazel et Nx soient des options robustes avec des fonctionnalités étendues, Turborepo se démarque comme un outil polyvalent qui combine le meilleur des deux mondes.

En fin de compte, la clé pour mettre en œuvre et maintenir avec succès un monorepo réside dans la compréhension des besoins de votre équipe, le choix de l’outil qui correspond à votre flux de travail, et une adaptation continue aux pratiques de développement en constante évolution. À mesure que les monorepos continuent d’évoluer, le paysage des outils devrait s’élargir, offrant encore plus d’options aux développeurs cherchant des flux de travail de développement efficaces et évolutifs.

--

--