Monorepo mit Kotlin: Code-Organisation in der Praxis
In der modernen Softwareentwicklung stellt sich immer häufiger die Frage zwischen einem Monorepo und einem Multirepo. Für Kotlin-Projekte, insbesondere solche, die Kotlin Multiplatform oder eine Microservice-Architektur verwenden, wird das Monorepo zu einem leistungsstarken Werkzeug. In diesem Artikel werden wir untersuchen, wie man Code in einem Kotlin-Monorepo richtig organisiert, praktische Beispiele und Best Practices betrachten, die Ihnen helfen, typische Fehler zu vermeiden.
Was ist ein Monorepo und warum wird es in Kotlin benötigt?
Ein Monorepo ist ein Ansatz, bei dem der gesamte Code eines Projekts (oder mehrerer verwandter Projekte) in einem einzigen Repository gespeichert wird. Im Kontext von Kotlin kann dies Folgendes umfassen:
- Gemeinsame Bibliotheken — Hilfsprogramme, Datenmodelle, DTOs.
- Anwendungsmodule — Backend (Ktor, Spring), Frontend (Kotlin/JS), mobile Anwendungen (Kotlin Multiplatform).
- Skripte und Konfigurationen — CI/CD, Dockerfile, Gradle-Skripte.
Die Hauptvorteile eines Monorepos für Kotlin-Projekte:
- Einheitliche Abhängigkeitsversion — alle Module verwenden dieselbe Version von Kotlin und Bibliotheken, was das Konfliktrisiko verringert.
- Vereinfachtes Refactoring — eine API-Änderung in einem Modul ist sofort in allen abhängigen Modulen sichtbar.
- Einfachere CI/CD-Einrichtung — eine Pipeline für alle Komponenten.
- Transparenz — die gesamte Codebasis ist an einem Ort verfügbar.
Es gibt jedoch auch Nachteile: Die Repository-Größe kann wachsen und die Klonzeit erhöht sich. Aber für mittlere und große Kotlin-Projekte ist ein Monorepo oft die optimale Lösung.
Monorepo-Struktur: Praktische Vorlage
Die richtige Ordnerorganisation ist die Grundlage für den Erfolg. Betrachten wir eine typische Struktur für ein Kotlin-Projekt mit Gradle:
my-kotlin-monorepo/├── build.gradle.kts # Root-Build-Skript├── settings.gradle.kts # Modulkonfiguration├── gradle.properties # Allgemeine Gradle-Parameter├── gradle/│ └── libs.versions.toml # Version Catalog (empfohlen)├── modules/│ ├── common/ # Gemeinsame Hilfsprogramme und Modelle│ │ ├── build.gradle.kts│ │ └── src/│ ├── backend/ # Backend-Service mit Ktor│ │ ├── build.gradle.kts│ │ └── src/│ ├── android-app/ # Android-Anwendung│ │ ├── build.gradle.kts│ │ └── src/│ └── web-client/ # Kotlin/JS-Client│ ├── build.gradle.kts│ └── src/├── scripts/ # Hilfsskripte│ └── deploy.sh└── docs/ # Dokumentation └── architecture.mdDie Datei settings.gradle.kts bindet die Module ein:
rootProject.name = "my-kotlin-monorepo"
include(":modules:common")include(":modules:backend")include(":modules:android-app")include(":modules:web-client")Im root build.gradle.kts können allgemeine Plugins und Abhängigkeiten festgelegt werden:
plugins { kotlin("jvm") version "1.9.22" apply false kotlin("multiplatform") version "1.9.22" apply false id("com.android.application") version "8.2.0" apply false}Abhängigkeitsverwaltung: Version Catalog und Convention Plugins
In einem Monorepo ist es entscheidend, die Duplizierung von Abhängigkeitsversionen zu vermeiden. Dazu wird in Kotlin der Version Catalog (Datei libs.versions.toml) verwendet.
Beispiel für gradle/libs.versions.toml:
[versions]kotlin = "1.9.22"ktor = "2.3.7"coroutines = "1.8.0"
[libraries]kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }ktor-server-core = { module = "io.k