Monorepository mit C#: Wie man Code in .NET-Projekten organisiert
Moderne Entwicklung mit C# und .NET steht immer häufiger vor der Wahl: alle zusammenhängenden Projekte in einem Repository (Monorepository) zu speichern oder sie auf einzelne Repositories (Multirepository) aufzuteilen. Ein Monorepository ist ein Ansatz, bei dem der Code mehrerer Anwendungen, Bibliotheken, Tests und Konfigurationen in einem einzigen Git-Repository gespeichert wird. Für große Unternehmenslösungen, Microservices oder NuGet-Bibliotheken kann dieser Ansatz die Verwaltung von Abhängigkeiten, Refactoring und Bereitstellung erheblich vereinfachen.
In diesem Artikel werden wir untersuchen, wie man ein Monorepository mit C# in der .NET-Ökosystem richtig organisiert, die Ordnerstruktur, Projekteinrichtung, CI/CD und bewährte Praktiken betrachten.
1. Vorteile und Nachteile eines Monorepositorys in .NET
Bevor wir uns in die technischen Details vertiefen, ist es wichtig zu verstehen, wann ein Monorepository wirklich nützlich ist und wann es problematisch werden kann.
Vorteile:
- Einheitliche Abhängigkeitsversionen. Alle Projekte innerhalb des Repositorys verwenden dieselben Paketversionen, was Versionskonflikte ausschließt.
- Vereinfachtes Refactoring. Die Änderung einer gemeinsamen Schnittstelle oder API einer Bibliothek ist sofort in allen Projekten sichtbar, die sie verwenden.
- Integrität der Commits. Atomare Commits, die sowohl die Bibliothek als auch die Anwendung ändern, funktionieren ohne zeitliche Unterbrechungen.
- Gemeinsame Einstellungen. Eine einzige Datei
Directory.Build.propslegt Kompilierungseinstellungen, Code-Analyse und Versionen für alle Projekte fest.
Nachteile:
- Wachstum der Repository-Größe. Mit der Zeit können das Klonen und die Historie sehr groß werden.
- Komplexität von CI/CD. Ein intelligentes Build-System ist erforderlich, um nicht bei jedem Commit alles neu zu erstellen.
- Zugriffsrechte. In einem Repository ist es schwieriger, den Zugriff für verschiedene Teams zu differenzieren.
Für .NET-Projekte ist ein Monorepository besonders praktisch, wenn Sie eine gemeinsame Klassenbibliothek (z.B. Domain oder Common) und mehrere Microservices oder Web-APIs haben, die davon abhängen.
2. Struktur eines Monorepositorys für C# (.NET)
Die richtige Ordnerstruktur ist die Grundlage eines erfolgreichen Monorepositorys. Betrachten wir eine typische Organisation für eine Lösung, die mehrere Microservices, eine Bibliothek und Tests umfasst.
MyApp/├── .github/│ └── workflows/│ └── ci.yml├── src/│ ├── MyApp.Common/ # gemeinsame Bibliothek│ │ ├── MyApp.Common.csproj│ │ └── ...│ ├── MyApp.Api.Orders/ # Microservice für Bestellungen│ │ ├── MyApp.Api.Orders.csproj│ │ └── ...│ └── MyApp.Api.Users/ # Microservice für Benutzer│ ├── MyApp.Api.Users.csproj│ └── ...├── tests/│ ├── MyApp.Common.Tests/│ │ ├── MyApp.Common.Tests.csproj│ │ └── ...│ └── MyApp.Api.Orders.Tests/│ ├── MyApp.Api.Orders.Tests.csproj│ └── ...├── Directory.Build.props # gemeinsame Einstellungen für alle Projekte├── MyApp.sln # Lösung für Visual Studio└── README.mdWichtige Punkte:
- Alle Projekte befinden sich im Ordner
src/, Tests im Ordnertests/. Dies ist ein in der .NET-Community üblicher Standard. - Die Datei
Directory.Build.propslegt gemeinsame Eigenschaften fest:TargetFramework,Nullable,ImplicitUsings, Paketversionen usw. - Eine einzelne SLN-Datei vereinfacht die Arbeit in der IDE, aber bei einer großen Anzahl von Projekten kann man sie in mehrere Lösungen aufteilen.
Beispiel für Directory.Build.props:
<Project> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> <TreatW