Si llevás tiempo desarrollando para Android, seguramente habrás escuchado sobre MVVM. Pero más allá de ser una sigla que aparece en la documentación de Google, es la diferencia entre una app que escala y una que se convierte en un laberinto de código ilegible. En este artículo te explico por qué MVVM es el patrón arquitectónico que deberías usar en todos tus proyectos Android con Kotlin, y cómo implementarlo paso a paso.
¿Qué es MVVM y por qué importa?
MVVM significa Model-View-ViewModel. Es un patrón de diseño que separa la aplicación en tres capas con responsabilidades bien definidas. El objetivo principal es uno solo: ninguna capa debe saber demasiado sobre las otras.
La View (tu Activity, Fragment o Composable) solo se encarga de mostrar información y capturar acciones del usuario. El ViewModel procesa esas acciones, aplica lógica y expone el estado actualizado. El Model (Repository + fuentes de datos) se encarga de obtener y persistir la información, sin importarle quién la va a mostrar.
1. El ViewModel: donde vive la lógica de UI
El ViewModel es el componente más importante del patrón. Sobrevive los cambios de configuración del dispositivo (como rotar la pantalla), lo que significa que el usuario no pierde su estado al girar el teléfono. Usa StateFlow para exponer el estado de forma reactiva.
2. La View: solo observa y reacciona
Con Jetpack Compose, la View se vuelve declarativa: describís qué mostrar según el estado, no cómo actualizar la pantalla. El sistema de recomposición de Compose se encarga de actualizar solo lo que cambió.
collectAsStateWithLifecycle vs collectAsState
Siempre usá collectAsStateWithLifecycle() en lugar de collectAsState(). La primera respeta el ciclo de vida de Android y pausa la recolección cuando la app está en segundo plano, ahorrando batería y recursos del sistema.
3. El Repository: la única fuente de verdad
El Repository actúa como intermediario inteligente. El ViewModel no sabe si los datos vienen de una base de datos local, una API remota o una caché. Esa complejidad vive en el Repository, y así el código de UI permanece limpio.
4. Errores comunes que hay que evitar
- Lógica de negocio en la View: si tu Composable tiene más de 3 líneas de lógica, esa lógica pertenece al ViewModel o Repository.
- Llamar a la base de datos desde la UI: Room opera en coroutines, nunca bloquees el hilo principal.
- MutableStateFlow público: exponé siempre el tipo inmutable (
StateFlow), no el mutable. - Un ViewModel por Activity gigante: creá ViewModels específicos por pantalla o funcionalidad para mantener la cohesión.
- Ignorar los ciclos de vida: usá
viewModelScopepara coroutines que deban cancelarse con el ViewModel.
5. ¿Vale la pena toda esta estructura para apps pequeñas?
Sí, y te explico por qué: el costo de configurar MVVM correctamente desde el inicio es mínimo comparado con refactorizar una app enredada semanas después. Además, cuando tu app crezca, agregar una nueva pantalla o funcionalidad será un proceso predecible y limpio en lugar de un rompecabezas.
Aplicar estos patrones en Flujo, mi app de finanzas personales, fue la decisión más importante del proyecto. Me permitió iterar rápidamente, agregar nuevas categorías de gasto sin tocar la UI, y mantener la lógica del balance calculado en un solo lugar confiable.
Regla de oro: si no podés hacer un test unitario sin instanciar la UI, tu arquitectura necesita trabajo
Una buena implementación de MVVM te permite escribir tests para el ViewModel y el Repository sin ningún componente de Android. Eso es código limpio, mantenible y profesional.