implementation vs api
La diferencia importa sobre todo en módulos librería. implementation mantiene la dependencia encapsulada; api la expone hacia módulos consumidores.
dependencies {
implementation(libs.coroutines.core)
api(project(":core:model"))
}La regla general es simple: usá implementation por defecto. Solo usá api cuando otro módulo realmente necesite ver ese tipo en su superficie pública.
Otras configurations
compileOnly: disponible al compilar, pero no empaquetada.runtimeOnly: necesaria al ejecutar, no al compilar.testImplementation: solo para unit tests.androidTestImplementation: solo para tests instrumentados.kspokapt: procesadores de código.
Idea importanteElegir mal una configuration no siempre rompe la app de inmediato, pero sí puede ensuciar la API de módulos, aumentar acoplamiento y afectar recompilaciones innecesarias.
Dependencias transitivas
Cuando una dependencia trae otras por detrás, aparecen las transitivas. Eso simplifica, pero a veces mete más de lo que querés.
implementation("com.squareup.retrofit2:retrofit:2.11.0") {
exclude(group = "org.jetbrains", module = "annotations")
}No conviene abusar de exclusiones, pero sí entender qué entra al classpath para no terminar con conflictos raros.
Criterios reales para elegir bien
- Usá
implementationsalvo motivo concreto para exponer. - Reservá
apipara módulos que forman parte de una API compartida. - Mantené separadas las dependencias de test.
- Evitá meter librerías enormes en módulos base si solo una feature las usa.
AtenciónUn anti-pattern común es poner casi todo en el módulo app “porque funciona”. Eso te deja sin límites claros y vuelve más difícil modularizar después.
Cierre
Entender configurations te da control sobre acoplamiento, recompilación y mantenimiento. En la próxima lección vemos cómo esas decisiones cambian cuando el proyecto crece y se organiza en múltiples módulos.