Einführung in das Monorepo mit Kotlin
Die moderne Entwicklung komplexer Anwendungen steht oft vor dem Problem der Codeverwaltung. Die Wahl zwischen einem Monorepo und einem Multirepo ist eine der wichtigsten architektonischen Entscheidungen. In diesem Artikel werden wir untersuchen, wie man ein Monorepo mit Kotlin unter Verwendung bewährter Praktiken und moderner Tools organisiert.
Ein Monorepo ist ein Ansatz, bei dem alle Projekte, Bibliotheken und Dienste in einem einzigen Repository gespeichert werden. Für Kotlin-Entwickler ist dies aufgrund des leistungsstarken Build-Systems Gradle und der Möglichkeit, gemeinsamen Code zwischen verschiedenen Modulen zu verwenden, besonders relevant.
Vorteile eines Monorepos für Kotlin-Projekte
Bevor wir zur Organisation übergehen, betrachten wir die wichtigsten Vorteile eines Monorepos für Kotlin:
- Einheitliche Abhängigkeitsversionen — alle Module verwenden dieselbe Version von Kotlin, Bibliotheken und Plugins, wodurch Versionskonflikte vermieden werden.
- Vereinfachtes Refactoring — Änderungen an einer gemeinsamen Bibliothek werden automatisch von allen abhängigen Modulen überprüft.
- Zentralisierte Konfiguration — gemeinsame Gradle-Einstellungen, Linter und CI/CD werden einmal konfiguriert.
- Atomare Commits — zusammenhängende Änderungen in verschiedenen Modulen können in einem einzigen Commit vorgenommen werden.
- Wiederverwendung von Code — gemeinsame Hilfsprogramme, DTOs und Geschäftslogik sind für alle Projekte leicht zugänglich.
Struktur eines Monorepos mit Kotlin und Gradle
Betrachten wir eine optimale Verzeichnisstruktur für ein Kotlin-Monorepo mit Gradle Multi-Module:
my-monorepo/├── build.gradle.kts # Root-Build-Datei├── settings.gradle.kts # Modulkonfiguration├── gradle.properties # Gemeinsame Eigenschaften├── gradle/│ └── libs.versions.toml # Version Catalog├── modules/│ ├── common/ # Gemeinsame Hilfsprogramme und Modelle│ ├── domain/ # Geschäftslogik│ ├── data/ # Datenschicht (API, DB)│ ├── service-a/ # Mikroservice A│ ├── service-b/ # Mikroservice B│ └── shared-test/ # Gemeinsame Test-Hilfsprogramme├── apps/│ ├── backend/ # Hauptanwendung│ └── cli-tool/ # CLI-Tool└── config/ ├── checkstyle/ # Linter-Konfiguration └── docker/ # Dockerfiles für DiensteEinrichtung von settings.gradle.kts
Die Datei settings.gradle.kts definiert alle Module des Projekts:
rootProject.name = "my-monorepo"
// Alle Module einschließeninclude( ":modules:common", ":modules:domain", ":modules:data", ":modules:service-a", ":modules:service-b", ":apps:backend", ":apps:cli-tool")
// Plugin für VersionsverwaltungpluginManagement { repositories { gradlePluginPortal() mavenCentral() }}Verwendung des Version Catalog (libs.versions.toml)
Für die zentralisierte Verwaltung von Abhängigkeiten verwenden wir gradle/libs.versions.toml:
[versions]kotlin = "1.9.22"coroutines = "1.7.3"ktor = "2.3.7"exposed = "0.44.1"
[libraries]kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }ktor-server-core = { module = "io.ktor:ktor-server-core", version.ref = "ktor" }exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }
[plugins]kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }Beispiel build.gradle.kts für das Modul common
plugins { alias(libs.plugins.kotlin.jvm)}
depend