Modularización Android en 2026: Arquitectura Multi-Módulo y Preguntas de Entrevista
Guía completa sobre modularización Android en 2026. Aprende a estructurar una arquitectura multi-módulo, usar catálogos de versiones Gradle y dominar las preguntas de entrevista técnica esenciales.

La modularización Android transforma bases de código monolíticas en sistemas mantenibles y escalables donde los equipos trabajan en paralelo sin conflictos de código. Una aplicación Android bien modularizada se compila más rápido, se prueba de forma aislada y permite la incorporación de nuevos desarrolladores en días en lugar de semanas.
La modularización divide una aplicación Android en módulos Gradle independientes con límites claros. El bajo acoplamiento entre módulos y la alta cohesión dentro de cada módulo son los principios rectores. La aplicación de referencia Now in Android de Google demuestra este patrón con más de 40 módulos.
Por Qué la Arquitectura Multi-Módulo Es Importante para Aplicaciones Android
Una aplicación Android de módulo único recompila todo cuando cambia una sola línea. Una modificación en la capa de red dispara la recompilación de la interfaz de usuario. Dos desarrolladores editando diferentes funcionalidades crean conflictos de merge en archivos compartidos. Los tiempos de compilación se extienden a más de 4 minutos en builds incrementales.
La arquitectura multi-módulo aborda directamente estos puntos de dolor:
- Compilaciones más rápidas: Gradle solo recompila los módulos afectados. Un cambio en
:feature:checkoutdeja:feature:profileintacto. - Desarrollo paralelo: Los equipos poseen módulos separados con APIs definidas. Los conflictos de merge disminuyen significativamente.
- Pruebas aisladas: Las pruebas unitarias se ejecutan contra un solo módulo sin cargar toda la aplicación.
- Reutilización de código: Un módulo de sistema de diseño
:core:uise convierte en una biblioteca utilizable en múltiples aplicaciones.
La guía oficial de modularización Android recomienda estructurar módulos alrededor de funcionalidades o capas que cambian juntas, siguiendo el Principio de Responsabilidad Única.
Tipos de Módulos y Sus Responsabilidades
El repositorio Now in Android establece una taxonomía de módulos probada que escala a aplicaciones empresariales.
include(":app")
// Módulos core - utilidades compartidas
include(":core:common")
include(":core:data")
include(":core:database")
include(":core:datastore")
include(":core:designsystem")
include(":core:domain")
include(":core:model")
include(":core:network")
include(":core:ui")
// Módulos feature - lógica específica de pantallas
include(":feature:home")
include(":feature:search")
include(":feature:bookmarks")
include(":feature:settings")Módulo app: Contiene MainActivity, configuración de navegación y scaffolding a nivel de aplicación. Depende de todos los módulos feature y los módulos core requeridos.
Módulos core: Proporcionan funcionalidad compartida entre features. :core:network maneja llamadas API. :core:database gestiona entidades Room. :core:designsystem define los componentes visuales de la aplicación.
Módulos feature: Encapsulan una única pantalla o flujo de usuario. Cada módulo feature depende solo de los módulos core que necesita, nunca de otros módulos feature.
Esta estructura impone dependencias unidireccionales: las features dependen de core, y app depende de features.
Catálogos de Versiones Gradle para Gestión de Dependencias
Gestionar dependencias en más de 25 módulos sin conflictos de versiones requiere configuración centralizada. Los Catálogos de Versiones Gradle resuelven esto con un único archivo libs.versions.toml.
# gradle/libs.versions.toml
[versions]
agp = "8.7.0"
kotlin = "2.1.0"
compose-bom = "2026.09.00"
ksp = "2.1.0-1.0.29"
hilt = "2.54"
room = "2.7.0"
retrofit = "2.11.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version = "1.15.0" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
retrofit-core = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
[bundles]
compose = ["androidx-compose-ui", "androidx-compose-material3"]
room = ["room-runtime", "room-ktx"]
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }Los módulos luego referencian dependencias con accesores tipados:
dependencies {
implementation(libs.bundles.compose)
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
}Gradle genera estos accesores durante la sincronización, habilitando autocompletado del IDE y validación en tiempo de compilación.
¿Listo para aprobar tus entrevistas de Android?
Practica con nuestros simuladores interactivos, flashcards y tests técnicos.
Convention Plugins: Configuración de Build DRY
Un proyecto de 25 módulos sin convention plugins repite los mismos compileSdk, minSdk, composeOptions y aplicaciones de plugins en cada build.gradle.kts. Diferentes módulos pueden accidentalmente usar configuraciones diferentes.
Los convention plugins centralizan esta lógica en un build incluido build-logic.
import com.android.build.api.dsl.LibraryExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
class AndroidLibraryConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.android.library")
pluginManager.apply("org.jetbrains.kotlin.android")
extensions.configure<LibraryExtension> {
compileSdk = 35
defaultConfig {
minSdk = 26
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}
}
}
}Registro del plugin en build-logic/convention/build.gradle.kts:
plugins {
`kotlin-dsl`
}
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
}
gradlePlugin {
plugins {
register("androidLibrary") {
id = "myapp.android.library"
implementationClass = "AndroidLibraryConventionPlugin"
}
register("androidFeature") {
id = "myapp.android.feature"
implementationClass = "AndroidFeatureConventionPlugin"
}
register("androidHilt") {
id = "myapp.android.hilt"
implementationClass = "AndroidHiltConventionPlugin"
}
}
}Los módulos feature ahora requieren configuración mínima:
plugins {
alias(libs.plugins.myapp.android.feature)
alias(libs.plugins.myapp.android.hilt)
}
dependencies {
implementation(projects.core.data)
implementation(projects.core.designsystem)
}El build-logic de Now in Android de Google utiliza exactamente este patrón.
Patrones de Comunicación Entre Módulos
Los módulos feature no deben depender directamente unos de otros. Esta restricción preserva la compilación paralela y previene dependencias circulares. Tres patrones manejan la comunicación entre features.
Navegación vía Rutas Compartidas
object Routes {
const val HOME = "home"
const val PRODUCT_DETAIL = "product/{productId}"
const val CHECKOUT = "checkout"
fun productDetail(productId: String) = "product/$productId"
}Los módulos feature importan rutas desde :core:navigation sin saber qué módulo implementa cada destino.
Modelos de Dominio Compartidos
data class Product(
val id: String,
val name: String,
val price: BigDecimal,
val imageUrl: String
)Tanto :feature:catalog como :feature:checkout dependen de :core:model para la clase Product.
Event Bus o ViewModel Compartido
Para comunicación en tiempo de ejecución, un event bus compartido en :core:common o un ViewModel con scope maneja eventos entre features:
object CartEventBus {
private val _events = MutableSharedFlow<CartEvent>()
val events: SharedFlow<CartEvent> = _events.asSharedFlow()
suspend fun emit(event: CartEvent) {
_events.emit(event)
}
}
sealed interface CartEvent {
data class ItemAdded(val productId: String) : CartEvent
data class ItemRemoved(val productId: String) : CartEvent
}Preguntas de Entrevista sobre Modularización Android
La modularización aparece frecuentemente en entrevistas Android de nivel senior. Los entrevistadores evalúan la comprensión de sistemas de build, decisiones de arquitectura y compensaciones prácticas.
Al discutir modularización en entrevistas, se recomienda referenciar métricas concretas: mejoras en tiempos de build, ganancias de velocidad del equipo o números específicos de módulos de proyectos reales. Las respuestas abstractas sobre "mejor separación de responsabilidades" son menos convincentes que "los tiempos de build bajaron de 4 minutos a 45 segundos después de la modularización".
P: ¿Cuál es la diferencia entre dependencias api e implementation en Gradle?
Las dependencias implementation son internas al módulo. Los consumidores del módulo no pueden acceder a ellas. Las dependencias api se exponen transitivamente: si el módulo A usa api(libs.retrofit), el módulo B que depende de A puede usar clases de Retrofit directamente.
Regla general: usar implementation por defecto. Solo usar api cuando la dependencia es parte de la API pública del módulo. El uso excesivo de api rompe la encapsulación y ralentiza los builds.
P: ¿Cómo manejar la navegación entre módulos feature que no dependen entre sí?
Se debe crear un módulo :core:navigation conteniendo definiciones de rutas e interfaces de navegación. Los módulos feature dependen de este módulo compartido. El módulo app conecta los destinos con las implementaciones. Esto sigue el principio de inversión de dependencias: las features dependen de abstracciones, no de implementaciones concretas.
P: ¿Cuáles son las compensaciones de tener demasiados módulos?
Cada módulo agrega overhead de configuración Gradle: archivos de build, procesamiento de recursos, fusión de manifests. Los tiempos de sincronización inicial aumentan. El punto de inflexión varía por proyecto, pero 50+ módulos es común en aplicaciones grandes. Los beneficios (builds paralelos, pruebas aisladas, propiedad clara) típicamente superan el overhead para equipos de 5+ desarrolladores.
P: ¿En qué se diferencian los convention plugins de buildSrc?
Los cambios en buildSrc disparan una reconstrucción completa del proyecto. Los convention plugins en un build incluido solo recompilan cuando cambia el código del plugin, no cuando cambian los módulos consumidores. Esto hace que los convention plugins sean más rápidos para desarrollo iterativo. Además, los convention plugins pueden publicarse como un artefacto separado para reutilización entre repositorios.
P: ¿Cómo probar un módulo feature de forma aislada?
Los módulos feature dependen de módulos core a través de interfaces. Se deben crear implementaciones falsas en test fixtures:
class FakeProductRepository : ProductRepository {
private val products = mutableListOf<Product>()
override suspend fun getProducts(): List<Product> = products
fun addProduct(product: Product) {
products.add(product)
}
}Las pruebas de módulos feature inyectan fakes vía las APIs de testing de Hilt o inyección manual por constructor.
Para más preguntas de práctica sobre arquitectura Android, consultar las preguntas de entrevista sobre arquitectura MVVM y el módulo sobre inyección de dependencias.
¡Empieza a practicar!
Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.
Puntos Clave para Proyectos Android Multi-Módulo
- Estructurar módulos por feature (
:feature:home,:feature:checkout) y por capa (:core:data,:core:ui). Las features dependen de core, nunca entre sí. - Usar Catálogos de Versiones Gradle (
libs.versions.toml) para centralizar versiones de dependencias. Los bundles agrupan dependencias relacionadas para archivos de build más limpios. - Implementar convention plugins en
build-logicpara eliminar configuración duplicada entre módulos. Un cambio en el plugin actualiza todos los módulos consumidores. - Imponer dependencias unidireccionales: app depende de features, features dependen de core. Herramientas como Dependency Guard pueden automatizar esta aplicación.
- Medir el rendimiento de build antes y después de la modularización. Seguir los tiempos de build incrementales, no solo los builds limpios, para validar mejoras.
- Mantener los límites de módulos estables. Las reestructuraciones frecuentes anulan los beneficios de la modularización.
¿Sabrías detectar el bug en Android?
Un fragmento real, un bug oculto, un intento al día. Sin cuenta para probar.

Escrito por
Anthony Fillion-MailletFundador de SharpSkill
Desarrollador fullstack desde hace más de 10 años. Dirige SharpSkill y responde por todo lo que se publica aquí.
Actualizado el 17 de septiembre de 2026
Etiquetas
Compartir
Artículos relacionados

Android WorkManager en 2026: Tareas en Segundo Plano, Restricciones y Preguntas de Entrevista
Guía completa sobre WorkManager para Android en 2026: creación de Workers, restricciones de ejecución, encadenamiento de tareas y preguntas técnicas de entrevista.

Kotlin Flow vs StateFlow vs SharedFlow: preguntas de entrevista de Android en 2026
Las preguntas sobre Kotlin Flow vs StateFlow vs SharedFlow que hacen los entrevistadores de Android en 2026, con respuestas claras, una tabla comparativa y código listo para producción.

Android 16 en 2026: Nuevas APIs, Modo Escritorio y Preguntas de Entrevista
Análisis profundo de Android 16 API 36: edge-to-edge obligatorio, Desktop Mode, ProgressStyle, navegación predictiva y preguntas de entrevista técnica para desarrolladores Android en 2026.