Módulos de funcionalidades y del núcleo
Defina los límites entre módulos
Módulos de funcionalidades y del núcleo es una lección gratuita de Android Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Android Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Android Academy incluye 4 lecciones en total.
Dos tipos de módulos
La mayoría de las aplicaciones Android modularizadas organizan el código en dos tipos principales de módulos: módulos feature y módulos core, además de un módulo :app pequeño en la parte superior.
- Los módulos feature contienen una sección de la aplicación orientada al usuario (una pantalla o un flujo).
- Los módulos core contienen infraestructura compartida que utilizan varias funcionalidades.
En esta lección aprenderá a definir correctamente estos límites.
Anatomía de un módulo feature
Un módulo feature como :feature:profile contiene todo lo que necesita una funcionalidad concreta: sus pantallas de Compose, su ViewModel y su estado de interfaz. Es vertical: es responsable de toda la sección, desde la interfaz hasta su view-model.
Depende de los módulos core para los elementos compartidos, pero no debería depender de otros módulos feature.
// feature/profile/ProfileScreen.kt
@Composable
fun ProfileScreen(viewModel: ProfileViewModel = hiltViewModel()) {
val state by viewModel.uiState.collectAsStateWithLifecycle()
when (state) {
is ProfileUiState.Loading -> CircularProgressIndicator()
is ProfileUiState.Success -> ProfileContent((state as ProfileUiState.Success).user)
is ProfileUiState.Error -> ErrorMessage()
}
}El ViewModel de la funcionalidad
Cada funcionalidad es responsable de su propio ViewModel. Obtiene los datos mediante un repositorio de un módulo core y expone el estado de la interfaz. El módulo feature no sabe cómo se obtienen los datos, solo conoce el contrato del repositorio.
// feature/profile/ProfileViewModel.kt
@HiltViewModel
class ProfileViewModel @Inject constructor(
private val userRepository: UserRepository // from :core:data
) : ViewModel() {
val uiState: StateFlow<ProfileUiState> =
userRepository.observeUser()
.map { ProfileUiState.Success(it) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), ProfileUiState.Loading)
}Anatomía de un módulo core
Un módulo core es horizontal: proporciona una capacidad que se utiliza en varias funcionalidades. Algunos módulos core habituales son:
:core:model— clases de datos simples compartidas en toda la aplicación:core:network— clientes de Retrofit/Ktor:core:database— configuración de Room:core:data— repositorios que combinan red y base de datos:core:designsystem— tema y composables reutilizables
// core/model/User.kt
data class User(
val id: String,
val name: String,
val avatarUrl: String
)El módulo del sistema de diseño
:core:designsystem es uno de los módulos que más se reutilizan. Contiene su MaterialTheme, las paletas de colores, la tipografía y composables reutilizables, como botones y tarjetas. Todas las funcionalidades aplican el mismo aspecto sin copiar código.
// core/designsystem/AppTheme.kt
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colors = if (darkTheme) DarkColors else LightColors
MaterialTheme(
colorScheme = colors,
typography = AppTypography,
content = content
)
}El módulo de datos es responsable de los repositorios
El módulo :core:data expone interfaces de repositorio de las que dependen las funcionalidades, mientras oculta la implementación. Normalmente depende de :core:network y :core:database, y los combina en una única fuente de verdad.
// core/data/UserRepository.kt
interface UserRepository {
fun observeUser(): Flow<User>
suspend fun refresh()
}
// core/data/OfflineFirstUserRepository.kt
internal class OfflineFirstUserRepository @Inject constructor(
private val api: UserApi, // :core:network
private val dao: UserDao // :core:database
) : UserRepository {
override fun observeUser(): Flow<User> = dao.observe().map { it.toUser() }
override suspend fun refresh() { dao.upsert(api.fetch().toEntity()) }
}Mantenga ligeros los módulos model y designsystem
Los módulos centrales de nivel más bajo deben depender de la menor cantidad posible de elementos. Lo ideal es que :core:model no tenga ninguna dependencia de Android: solo clases de datos sencillas de Kotlin. Esto permite utilizarlo en cualquier lugar y compilarlo rápidamente.
Si :core:model empezara a depender de Retrofit o Room, cada módulo que utilizara sus clases de datos incorporaría esas bibliotecas pesadas.
// core/model/build.gradle.kts
plugins {
id("myapp.jvm.library") // pure Kotlin, no Android
}
// No Retrofit, no Room, no Compose here — just data classesEl módulo :app ligero
El módulo :app es el ensamblador. Debe contener muy poca lógica: la clase Application, la única MainActivity, el NavHost de nivel superior y la configuración de la inyección de dependencias. Todas las pantallas reales se encuentran en módulos de funcionalidades.
Un módulo de aplicación ligero significa que la mayoría de los cambios se producen en las funcionalidades, por lo que el módulo de aplicación rara vez se vuelve a compilar.
// app/MainActivity.kt
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme { // from :core:designsystem
AppNavHost() // routes into :feature:* screens
}
}
}
}Definir buenos límites
¿Cómo decide qué se convierte en un módulo? Estas son algunas heurísticas prácticas:
- Una funcionalidad = una pantalla o un flujo que el usuario puede nombrar (Inicio, Perfil, Pago).
- Un módulo core = una capacidad reutilizada por 2 o más funcionalidades.
- Si dos funcionalidades necesitan el mismo código, muévalo hacia abajo a un módulo core.
- Si un módulo hace demasiadas cosas que no están relacionadas, divídalo.
Opcional: división entre api e impl
En ocasiones, las aplicaciones grandes dividen una funcionalidad en un :feature:profile:api público (interfaces y rutas de navegación) y un :feature:profile:impl privado (pantallas y view-models). Las demás funcionalidades dependen únicamente del pequeño api, nunca de la implementación.
Esto es avanzado; para la mayoría de las aplicaciones, un solo módulo por funcionalidad es más que suficiente. Solo debe saber que este patrón existe para bases de código muy grandes.
// Other features see only the contract, not the screens
// feature/home depends on :feature:profile:api
interface ProfileEntry {
val route: String
fun NavGraphBuilder.register(navController: NavController)
}Unir el grafo
Así se conectan las capas en nuestro ejemplo. Observe que las dependencias siempre apuntan hacia abajo: app -> feature -> data -> network/database -> model.
// :app -> :feature:home, :feature:profile
// :feature:home -> :core:data, :core:designsystem
// :feature:profile -> :core:data, :core:designsystem
// :core:data -> :core:network, :core:database, :core:model
// :core:network -> :core:model
// :core:database -> :core:model
// :core:model -> (nothing)Comprobación rápida
Sus módulos :feature:home y :feature:profile necesitan obtener y almacenar en caché los datos de usuario. ¿Dónde debería residir el código del repositorio?
Resumen: módulos de funcionalidades y core
Ha aprendido a dividir el código en dos capas:
- Los módulos de funcionalidades son segmentos verticales (pantalla + ViewModel + estado de la interfaz).
- Los módulos core son capacidades horizontales (model, network, database, data, designsystem).
- El módulo
:appse mantiene ligero y se limita a ensamblar las funcionalidades. - El código compartido se mueve hacia abajo, a core;
:core:modelno depende de Android y se mantiene ligero.
A continuación, administrará las dependencias entre estos módulos y mantendrá limpio el grafo.
Preguntas frecuentes
¿La lección «Módulos de funcionalidades y del núcleo» es gratis?
Sí — el texto completo de «Módulos de funcionalidades y del núcleo» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Android Academy, actualiza a CoddyKit PRO. El curso de Android Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Módulos de funcionalidades y del núcleo»?
Defina los límites entre módulos Practicas Android Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Android Academy?
No se requiere experiencia previa. Android Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Módulos de funcionalidades y del núcleo»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Android Academy?
Sí. Cada lección de Android Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Por qué modularizar
- Módulos de funcionalidades y del núcleo
- Gestión de dependencias entre módulos
- Navegación entre módulos