Transición de Maven + Java → Gradle + Kotlin DSL
Enfocado en aplicaciones modernas con arquitectura hexagonal y DDD
Gradle es un sistema de automatización de builds moderno, flexible y altamente configurable.
Reemplaza a Maven permitiendo scripts más expresivos (usando Kotlin o Groovy) y mejor rendimiento.
| Concepto | Maven (XML) | Gradle (Kotlin DSL) |
|---|---|---|
| Lenguaje | XML | Kotlin |
| Gestión de dependencias | <dependency> |
implementation(...) |
| Plugins | <plugin> |
plugins { ... } |
| Build por módulos | Multimódulo por carpetas | Igual, pero más dinámico |
| Personalización | Limitada | Muy flexible (¡es código real!) |
| Velocidad | Más lenta | Más rápida (caché, paralelismo) |
plugins {
kotlin("jvm") version "1.9.25"
id("application")
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib"))
testImplementation("org.jetbrains.kotlin:kotlin-test")
}
application {
mainClass.set("com.example.MainKt")
}| Maven | Gradle Kotlin DSL |
|---|---|
<dependencies> |
dependencies { ... } |
<dependency> |
implementation("group:artifact:ver") |
<plugin> |
plugins { id("...") } |
<repositories> |
repositories { mavenCentral() } |
modules (<module> en POM) |
include("module-name") en settings |
implementation(...) // Para el código principal
api(...) // Expone la dependencia públicamente (en libs)
testImplementation(...) // Para test unitarios
runtimeOnly(...) // Solo en tiempo de ejecuciónGradle te permite definir diferentes bloques de código fuente dentro del mismo módulo, sin necesidad de crear nuevos módulos físicos como en Maven.
val integrationTest by sourceSets.creating {
kotlin.srcDir("src/integrationTest/kotlin")
resources.srcDir("src/integrationTest/resources")
compileClasspath += sourceSets["main"].output
runtimeClasspath += output + compileClasspath
}También debes crear sus configuraciones:
configurations {
create("integrationTestImplementation")
create("integrationTestRuntimeOnly")
}Y su tarea de test:
tasks.register<Test>("integrationTest") {
testClassesDirs = integrationTest.output.classesDirs
classpath = integrationTest.runtimeClasspath
useJUnitPlatform()
}Separar cada Bounded Context y capa (domain, application, infrastructure, etc.) en módulos Gradle o sourceSets, con dependencias unidireccionales.
project-root/
├── settings.gradle.kts
├── build.gradle.kts
├── domain/
│ └── build.gradle.kts
├── application/
│ └── build.gradle.kts
├── infrastructure/
│ └── build.gradle.kts
├── bootstrap/
│ └── build.gradle.kts (main entry point)
// application/build.gradle.kts
dependencies {
implementation(project(":domain"))
}
// infrastructure/build.gradle.kts
dependencies {
implementation(project(":application"))
}@Service
class CreateOrderUseCaseImpl(
private val orderRepository: OrderRepository
) : CreateOrderUseCase {
override fun execute(cmd: CreateOrderCommand) { ... }
}En el bootstrap o controlador de entrada (REST, CLI, etc.):
@RestController
class OrderController(
private val createOrderUseCase: CreateOrderUseCase
) {
@PostMapping
fun create(@RequestBody req: OrderRequest) { ... }
}Puedes usar un sourceSet llamado testFixtures para reutilizar builders o factories:
src/testFixtures/kotlin/com/example/support/UserBuilder.kt
Y añadirlo a testImplementation:
testImplementation(testFixtures(project))También puedes crear acceptanceTest, contractTest, etc. como sourceSets independientes.
./gradlew build # Compila todo
./gradlew test # Ejecuta tests unitarios
./gradlew integrationTest # Ejecuta tests personalizados
./gradlew dependencies # Muestra el árbol de dependencias
./gradlew tasks # Lista tareas disponibles- Usa
build.gradle.kts(Kotlin DSL), más moderno y seguro que Groovy. - Mantén tus capas limpias:
domainnunca depende deinfra. - Usa
sourceSetscuando quieras separar tipos de tests sin añadir módulos. - Usa módulos (
include("...")) si quieres separar bounded contexts o componentes reutilizables.