Introdução: o que é um monorepositório e por que ele é útil para um desenvolvedor Kotlin
Um monorepositório (monorepo) é uma abordagem onde o código de vários projetos ou módulos é armazenado em um único repositório. No contexto do Kotlin, isso é especialmente conveniente: você pode combinar a parte do servidor (Ktor), bibliotecas, ferramentas CLI e até mesmo aplicativos móveis (Kotlin Multiplatform) em uma única estrutura. Para desenvolvedores iniciantes, o monorepositório simplifica a navegação, os testes e o trabalho colaborativo.
Neste artigo, vamos analisar como organizar um monorepositório com Kotlin, usando o Gradle Multi-Project Build. Você aprenderá como estruturar pastas corretamente, configurar dependências e evitar erros típicos.
Parte principal: criando um monorepositório com Kotlin
1. Estrutura do monorepositório: princípios básicos
Uma estrutura correta é a chave para o sucesso. Em um monorepositório Kotlin, cada módulo é um subprojeto Gradle separado. Aqui está um esquema típico:
my-monorepo/├── build.gradle.kts # Arquivo de build raiz├── settings.gradle.kts # Configuração dos módulos├── gradle.properties # Propriedades comuns├── shared/ # Biblioteca compartilhada (módulo)│ ├── build.gradle.kts│ └── src/│ └── main/│ └── kotlin/│ └── com/example/shared/│ └── Utils.kt├── backend/ # Módulo do servidor (Ktor)│ ├── build.gradle.kts│ └── src/│ └── main/│ └── kotlin/│ └── com/example/backend/│ └── Application.kt└── cli-tool/ # Ferramenta CLI ├── build.gradle.kts └── src/ └── main/ └── kotlin/ └── com/example/cli/ └── Main.ktRegra fundamental: um módulo — uma responsabilidade. Não misture lógica de negócios e infraestrutura no mesmo módulo. Isso simplifica os testes e o reuso de código.
2. Configuração do Gradle para o monorepositório
Vamos começar com o arquivo raiz settings.gradle.kts. Ele define quais módulos fazem parte do projeto:
// settings.gradle.ktsrootProject.name = "my-monorepo"
include(":shared")include(":backend")include(":cli-tool")
// Opcional: é possível definir nomes de módulos via include()// include(":libs:utils") — se o módulo estiver aninhado na pasta libsAgora o build.gradle.kts raiz. Normalmente, ele contém apenas configurações comuns (plugins, repositórios) e não possui código próprio:
// build.gradle.kts (raiz)plugins { kotlin("jvm") version "1.9.22" apply false id("application") apply false}
allprojects { repositories { mavenCentral() }}
subprojects { apply(plugin = "kotlin") // Configurações comuns para todos os subprojetos dependencies { implementation(kotlin("stdlib")) }}Observe o apply false — isso impede a aplicação do plugin ao projeto raiz. Cada módulo decide quais plugins precisa.
3. Exemplo de módulo: biblioteca compartilhada (shared)
O módulo shared conterá funções reutilizáveis. Seu build.gradle.kts:
// shared/build.gradle.ktsplugins { kotlin("jvm")}
dependencies { // Sem dependências internas — este é um módulo base testImplementation("org.jetbrains.kotlin:kotlin-test")}O código em si em 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 + bAgora este módulo pode ser conectado a outros módulos:
// backend/build.gradle.ktsplugins { kotlin("jvm") id("application")}
dependencies { implementation(project(