Monorepo avec C# : organisation du code en pratique
Un monorepo est une approche de gestion du code source où tous les projets d'une entreprise ou d'une équipe sont stockés dans un seul dépôt. Dans le monde C# et .NET, cette approche devient de plus en plus populaire grâce à la simplification du développement collaboratif, à l'unification des versions des dépendances et à un CI/CD centralisé. Cependant, sans une organisation correcte du code, un monorepo peut se transformer en chaos. Dans cet article, nous allons examiner les techniques pratiques pour organiser le code C# dans un monorepo : de la structure des dossiers à la configuration de la build.
1. Structure des dossiers : la base de l'ordre
La première étape vers un monorepo réussi est une hiérarchie de répertoires bien pensée. Il est recommandé de suivre une convention où chaque projet se trouve dans un dossier séparé et où les composants communs sont placés dans src/shared. Exemple de structure de base :
/monorepo├── src/│ ├── shared/│ │ ├── CommonLib/ # Utilitaires communs, DTO, interfaces│ │ └── LoggingLib/ # Journalisation│ ├── services/│ │ ├── AuthService/ # Microservice d'authentification│ │ └── OrderService/ # Microservice de commandes│ └── apps/│ ├── WebApi/ # Application web principale│ └── ConsoleApp/ # Outil console├── tests/│ ├── unit/│ │ ├── CommonLib.Tests/│ │ └── AuthService.Tests/│ └── integration/│ └── IntegrationTests/├── docs/├── scripts/├── .gitignore├── Directory.Build.props└── global.jsonPoints clés :
- src/ — code source de tous les projets.
- shared/ — bibliothèques utilisées par plusieurs projets.
- services/ — microservices ou modules.
- apps/ — applications finales (Web API, Console, Blazor).
- tests/ — tests, isolés du code source.
Cette structure permet de trouver facilement le code, d'éviter les dépendances cycliques et de simplifier la configuration du CI/CD.
2. Gestion des projets avec Directory.Build.props
Dans un monorepo, il est souvent nécessaire de définir des paramètres communs pour tous les projets : versions .NET, packages communs, règles d'analyse de code. Au lieu de les dupliquer dans chaque .csproj, utilisez le fichier Directory.Build.props à la racine du dépôt. Exemple :
<Project> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> </PropertyGroup>
<ItemGroup> <PackageReference Include="SonarAnalyzer.CSharp" Version="9.*" /> </ItemGroup></Project>Désormais, chaque projet enfant hérite automatiquement de ces paramètres. Si vous devez les remplacer pour un projet spécifique, ajoutez simplement les propriétés dans son .csproj — elles auront la priorité.
Vous pouvez également créer un fichier Directory.Build.targets pour des cibles de build communes (par exemple, copie de fichiers après la build).
3. Gestion des dépendances : approche centralisée
L'un des principaux problèmes d'un monorepo est le conflit de versions des packages. Dans .NET 8, une prise en charge intégrée de la gestion centralisée des packages (Central Package Management, CPM) est apparue. Pour cela, créez un fichier Directory.Packages.props à la racine :
<Project> <PropertyGroup> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> </PropertyGroup> <ItemGroup> <PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" /> <PackageVersion Include="Serilog" Version="3.1.1" />