Introduction : qu'est-ce qu'un monorepo et pourquoi en a-t-on besoin en tant que développeur Kotlin
Un monorepo (monorepository) est une approche où le code de plusieurs projets ou modules est stocké dans un seul dépôt. Dans le contexte de Kotlin, c'est particulièrement pratique : vous pouvez regrouper la partie serveur (Ktor), les bibliothèques, les outils CLI et même les applications mobiles (Kotlin Multiplatform) dans une structure unique. Pour les développeurs débutants, le monorepo simplifie la navigation, les tests et le travail collaboratif.
Dans cet article, nous allons voir comment organiser un monorepo avec Kotlin en utilisant Gradle Multi-Project Build. Vous apprendrez à structurer correctement les dossiers, à configurer les dépendances et à éviter les erreurs typiques.
Partie principale : création d'un monorepo avec Kotlin
1. Structure du monorepo : principes de base
Une structure correcte est la clé du succès. Dans un monorepo Kotlin, chaque module est un sous-projet Gradle distinct. Voici un schéma typique :
my-monorepo/├── build.gradle.kts # Fichier de build racine├── settings.gradle.kts # Configuration des modules├── gradle.properties # Propriétés communes├── shared/ # Bibliothèque partagée (module)│ ├── build.gradle.kts│ └── src/│ └── main/│ └── kotlin/│ └── com/example/shared/│ └── Utils.kt├── backend/ # Module serveur (Ktor)│ ├── build.gradle.kts│ └── src/│ └── main/│ └── kotlin/│ └── com/example/backend/│ └── Application.kt└── cli-tool/ # Outil CLI ├── build.gradle.kts └── src/ └── main/ └── kotlin/ └── com/example/cli/ └── Main.ktRègle clé : un module = une responsabilité. Ne mélangez pas la logique métier et l'infrastructure dans un même module. Cela simplifie les tests et la réutilisation du code.
2. Configuration de Gradle pour le monorepo
Commençons par le fichier racine settings.gradle.kts. Il définit quels modules font partie du projet :
// settings.gradle.ktsrootProject.name = "my-monorepo"
include(":shared")include(":backend")include(":cli-tool")
// Optionnel : on peut définir les noms des modules via include()// include(":libs:utils") — si le module est imbriqué dans le dossier libsMaintenant, le build.gradle.kts racine. Il contient généralement uniquement les configurations communes (plugins, dépôts) et n'a pas de code propre :
// build.gradle.kts (racine)plugins { kotlin("jvm") version "1.9.22" apply false id("application") apply false}
allprojects { repositories { mavenCentral() }}
subprojects { apply(plugin = "kotlin") // Configurations communes pour tous les sous-projets dependencies { implementation(kotlin("stdlib")) }}Notez le apply false — cela empêche l'application du plugin au projet racine. Chaque module décide lui-même des plugins dont il a besoin.
3. Exemple de module : bibliothèque partagée (shared)
Le module shared contiendra des fonctions réutilisables. Son build.gradle.kts :
// shared/build.gradle.ktsplugins { kotlin("jvm")}
dependencies { // Pas de dépendances internes — c'est un module de base testImplementation("org.jetbrains.kotlin:kotlin-test")}Le code lui-même dans Utils.kt :
// shared/src/main/kotlin/com/example/shared/Utils.ktpackage com.example.shared
fun greet(name: String): String = "Bonjour, $name!"
fun add(a: Int, b: Int): Int = a + bMaintenant, ce module peut être connecté à d'autres modules :
// backend/build.gradle.ktsplugins { kotlin("jvm") id("application")}
dependencies { implementation(project(