wandres.dev
ONTOLOGÍA · El mapa de MVI

La ontología de MVI

El mapa mental de Model-View-Intent en Kotlin y Android: Orbit, coroutines y Flow, estado inmutable en Compose, side effects de una sola vez y Kotlin Multiplatform.

⏱ 11 min

Android llegó al flujo unidireccional por el camino largo. Primero fue MVC, luego MVP con sus interfaces infinitas, luego MVVM con observables por todas partes, y en cada salto quedaba el mismo poso de bugs: dos fuentes de verdad que discrepan, un evento que se repite al rotar la pantalla, un estado que nadie sabe quién cambió. MVI cierra ese ciclo tomando prestada la lección de Elm: una sola entrada (la intención del usuario), un solo estado inmutable, y una función pura entre medias. Este mapa te da la visión aérea antes de recorrerlo.

🎯 Al terminar esta lección sabrás
  • Ver el mapa mental completo de MVI en el ecosistema Kotlin.
  • Entender por qué el estado inmutable encaja tan bien con Compose.
  • Distinguir estado de side effects de una sola vez.
  • Situar Orbit, las coroutines, Flow y Kotlin Multiplatform.

El territorio, de un vistazo

mindmap
root((MVI))
  El ciclo
    Intent
    Reduce
    Estado inmutable
    Side effects
  Kotlin
    data class
    sealed interface
    Coroutines
    Flow y StateFlow
  Android
    ViewModel
    Compose
    Estabilidad
    Navegacion
  Orbit
    Container
    Testing
    Sin libreria
  Escala
    Capa de datos
    Inyeccion
    Multiplatform

Las ideas clave

➡️

Una sola entrada

Todo lo que puede cambiar la pantalla entra por el mismo sitio: un intent. No hay setters dispersos ni métodos públicos que muten el estado por la puerta de atrás.

🧊

Un estado inmutable

El Model es un data class que se reemplaza entero con copy. La UI recibe una foto completa y coherente, nunca un puñado de observables que pueden estar desincronizados.

📮

Los eventos no son estado

Navegar o mostrar un aviso ocurre una vez y se acabó. Guardarlo en el estado es el bug clásico que reaparece al rotar. MVI los separa en un canal aparte.

🎨

Compose lo pide a gritos

Una UI declarativa que es función del estado encaja de forma natural con un estado inmutable único. El skipping de recomposición casi funciona solo si el modelo está bien hecho.

Por qué importa

La rotación de pantalla es el mejor test de arquitectura de Android

Hay una prueba brutalmente simple que revela si una arquitectura Android está bien pensada: gira el dispositivo en cada pantalla de tu app. Si algo parpadea, se pierde, se duplica o vuelve a mostrarse, has encontrado un defecto de diseño de estado, no un capricho del sistema. Android destruye y recrea la Activity, y con ella todo lo que no hayas modelado explícitamente como estado sobreviviente. Esa crueldad, que durante años se vivió como una tortura de la plataforma, es en realidad un regalo: te obliga desde el primer día a responder preguntas que en otras plataformas puedes posponer años. ¿Qué parte de lo que ves es estado y qué parte es un evento que ya ocurrió? ¿De quién es la fuente de verdad? ¿Qué debe sobrevivir a la muerte del proceso y qué no? MVI se lleva bien con Android precisamente porque esas preguntas son su punto de partida, no una corrección posterior. El estado es un valor único que puedes serializar y restaurar; los eventos de una sola vez viven en un canal que se consume y se olvida; y el reducer es una función pura que puedes ejecutar mil veces en un test sin abrir el emulador. La ceremonia existe y es real —hay que nombrar cada intent, declarar cada efecto—, pero a cambio la pregunta “por qué se ve esto así” siempre tiene una respuesta que cabe en una función.

El camino

  • Niveles 1–2 · Fundamentos — el patrón MVI y Orbit como implementación idiomática en Kotlin.
  • Niveles 3–5 · Kotlin — data classes y sealed, coroutines y concurrencia estructurada, Flow y StateFlow.
  • Niveles 6–8 · Android — el ViewModel, el estado en Compose, y la estabilidad que gobierna la recomposición.
  • Niveles 9–13 · El ciclo — intents y reducción, side effects de una sola vez, Orbit a fondo, su testing, y MVI a mano.
  • Niveles 14–18 · A escala — navegación, capa de datos, inyección de dependencias, Multiplatform y testing.
  • Niveles 19–21 · Perspectiva — la comparación con MVVM y MVP, los errores comunes, y la síntesis final.
⚔️ Sitúate en el mapa
  1. Abre una app tuya y gírala en cada pantalla. Anota todo lo que se rompe, parpadea o se repite.
  2. Para cada fallo, decide: ¿esto era estado que debí conservar, o un evento que no debí guardar?
  3. Coge una pantalla y escribe su estado como un solo data class; comprueba si alguna combinación de campos es imposible.
  4. Comprométete con la separación: el estado es una foto, los efectos son un disparo.