Introducción: ¿qué es un monorepositorio y por qué lo necesita un desarrollador Kotlin?
Un monorepositorio (monorepo) es un enfoque en el que el código de varios proyectos o módulos se almacena en un solo repositorio. En el contexto de Kotlin, esto es especialmente conveniente: puede combinar la parte del servidor (Ktor), bibliotecas, herramientas CLI e incluso aplicaciones móviles (Kotlin Multiplatform) en una estructura unificada. Para los desarrolladores principiantes, un monorepositorio simplifica la navegación, las pruebas y el trabajo colaborativo.
En este artículo, analizaremos cómo organizar un monorepositorio con Kotlin utilizando Gradle Multi-Project Build. Aprenderá a estructurar correctamente las carpetas, configurar dependencias y evitar errores típicos.
Parte principal: creación de un monorepositorio con Kotlin
1. Estructura del monorepositorio: principios básicos
Una estructura correcta es la clave del éxito. En un monorepositorio Kotlin, cada módulo es un subproyecto Gradle independiente. Aquí hay un esquema típico:
my-monorepo/├── build.gradle.kts # Archivo de compilación raíz├── settings.gradle.kts # Configuración de módulos├── gradle.properties # Propiedades comunes├── shared/ # Biblioteca compartida (módulo)│ ├── build.gradle.kts│ └── src/│ └── main/│ └── kotlin/│ └── com/example/shared/│ └── Utils.kt├── backend/ # Módulo del servidor (Ktor)│ ├── build.gradle.kts│ └── src/│ └── main/│ └── kotlin/│ └── com/example/backend/│ └── Application.kt└── cli-tool/ # Herramienta CLI ├── build.gradle.kts └── src/ └── main/ └── kotlin/ └── com/example/cli/ └── Main.ktRegla clave: un módulo, una responsabilidad. No mezcle la lógica de negocio y la infraestructura en un mismo módulo. Esto simplifica las pruebas y la reutilización del código.
2. Configuración de Gradle para el monorepositorio
Empecemos con el archivo raíz settings.gradle.kts. Este define qué módulos forman parte del proyecto:
// settings.gradle.ktsrootProject.name = "my-monorepo"
include(":shared")include(":backend")include(":cli-tool")
// Opcional: se pueden asignar nombres a los módulos mediante include()// include(":libs:utils") — si el módulo está anidado en la carpeta libsAhora el build.gradle.kts raíz. Normalmente contiene solo configuraciones generales (plugins, repositorios) y no tiene código propio:
// build.gradle.kts (raíz)plugins { kotlin("jvm") version "1.9.22" apply false id("application") apply false}
allprojects { repositories { mavenCentral() }}
subprojects { apply(plugin = "kotlin") // Configuraciones comunes para todos los subproyectos dependencies { implementation(kotlin("stdlib")) }}Observe apply false — esto evita que el plugin se aplique al proyecto raíz. Cada módulo decide qué plugins necesita.
3. Ejemplo de módulo: biblioteca compartida (shared)
El módulo shared contendrá funciones reutilizables. Su build.gradle.kts:
// shared/build.gradle.ktsplugins { kotlin("jvm")}
dependencies { // Sin dependencias internas — es un módulo base testImplementation("org.jetbrains.kotlin:kotlin-test")}El código en Utils.kt:
// shared/src/main/kotlin/com/example/shared/Utils.ktpackage com.example.shared
fun greet(name: String): String = "Hello, $name!"
fun add(a: Int, b: Int): Int = a + bAhora este módulo se puede conectar a otros módulos:
// backend/build.gradle.ktsplugins { kotlin("jvm") id("application")}
dependencies { implementation(project(