Arquitectura de aplicaciones móviles
La arquitectura móvil es mucho más que pantallas y manejo de estado.
Un mapa práctico para capas móviles, propiedad del estado, reglas de dominio, datos, APIs, autenticación, offline, capacidades nativas, pruebas, releases y evolución.Definición
La arquitectura de aplicaciones móviles es el conjunto de decisiones estructurales que organiza presentación, estado, reglas de negocio, datos, integraciones y capacidades de plataforma para que una aplicación pueda evolucionar de forma confiable. No significa agregar muchas capas por defecto. Significa elegir límites adecuados para usuarios, flujos, backend, dispositivos y vida útil del producto.
Por qué importa la arquitectura móvil
Una app móvil vive bajo restricciones distintas: conectividad variable, dispositivos diferentes, ciclo de vida del sistema operativo, permisos, almacenamiento local, batería, rendimiento, actualizaciones distribuidas, compatibilidad con backend y versiones antiguas instaladas. La arquitectura debe hacer visibles esas restricciones sin convertir la entrega en burocracia.
Problemas que ayuda a aclarar
- Las pantallas terminan mezclando reglas de negocio, mapeo de APIs y manejo de errores.
- El manejo de estado se trata como toda la arquitectura en vez de una decisión dentro de ella.
- Los modelos de transporte de APIs se filtran hacia conceptos de dominio.
- Autenticación, autorización y permisos del dispositivo se mezclan en una sola preocupación ambigua.
- Se asume comportamiento offline sin definir fuente de verdad, retries ni conflictos.
- Las capacidades nativas quedan acopladas a la UI y son difíciles de probar o reemplazar.
- Los releases móviles se planifican como deploys web aunque rollback y revisión de tienda funcionan distinto.
- Las pruebas se concentran en pantallas mientras reglas y flujos críticos quedan descubiertos.
Contexto y restricciones
La arquitectura empieza por restricciones: usuarios, flujos, conectividad, sensibilidad de datos, tamaño del equipo, velocidad, plataformas objetivo, backend, integraciones, capacidades nativas, estrategia de release y vida útil. Un patrón elegido antes de ese contexto suele ser decoración, no arquitectura.
- Una app experimental pequeña puede ser simple a propósito.
- Una app de flujos de negocio necesita límites más claros en dominio, datos e integración.
- Un canal móvil de una plataforma SaaS debe coordinar identidad, permisos y releases con backend.
Manejo de estado
El manejo de estado es parte de la arquitectura móvil, no toda la arquitectura. La pregunta útil es propiedad: estado local de UI, pantalla, aplicación, dominio, servidor y persistido tienen ciclos de vida y fallas diferentes.
- Definir quién posee loading, errores, invalidación, estado derivado y sincronización.
- Elegir Provider, Bloc o Riverpod como herramientas, no como reglas universales.
- Evitar usar contenedores de estado para esconder límites de dominio poco claros.
Dominio y reglas de negocio
La lógica de dominio incluye casos de uso, workflows, validación, invariantes y reglas que no deberían depender de una pantalla o framework. El nivel de modelado debe corresponder a la complejidad real.
- Modelar flujos críticos donde cambiar o equivocarse cuesta.
- Mantener validaciones e invariantes probables sin renderizar pantallas.
- Usar límites ligeros cuando DDD completo sería desproporcionado.
Datos y persistencia
La arquitectura de datos móvil decide cómo conviven datos remotos, locales, caché, persistencia, serialización, migraciones, invalidación, secure storage, ciclo de vida, propiedad y borrado. No todo necesita persistencia local ni todo dato persistido debe ser fuente de verdad.
- Separar modelos de transporte de conceptos de dominio.
- Usar almacenamiento seguro para material sensible de sesión cuando corresponda.
- Planificar invalidación y borrado antes de que el dato local se acumule.
Backend y APIs
Una app móvil depende de contratos de API, mapeo, retries, timeouts, paginación, rate limits, traducción de errores, autenticación, compatibilidad, versionado, idempotencia y trabajo en background. Backend y mobile no se despliegan al mismo ritmo.
- Mapear datos de transporte antes de llegar al dominio.
- Hacer explícitos retries, timeouts y traducción de errores.
- Coordinar versionado de APIs con versiones móviles instaladas.
Autenticación y permisos
Autenticación prueba identidad. Autorización decide qué puede hacer esa identidad. Permisos del dispositivo controlan capacidades de plataforma. La arquitectura debe distinguirlos y manejar tokens, expiración, acceso revocado, roles, claims, least privilege y feedback.
- No confundir permiso del sistema operativo con permiso de negocio.
- Planificar sesiones expiradas o revocadas como flujos normales.
- Pedir permisos cerca de la intención del usuario.
Offline y sincronización
Offline no es solo guardar datos. Implica fuente de verdad, cambios en cola, resolución de conflictos, retries, orden, timestamps, idempotencia, datos stale, feedback y recuperación de conectividad. Algunas apps son offline-capable, otras offline-tolerant y solo algunas offline-first.
- Elegir estrategia offline desde la necesidad del producto.
- Diseñar conflictos antes de que usuarios dependan de cambios locales.
- No afirmar offline-first si la evidencia pública solo muestra flujos conectados.
Capacidades nativas y código compartido
Flutter puede facilitar base compartida, UI consistente, componentes reutilizables y entrega coordinada Android/iOS. No elimina decisiones de dominio, estado, backend, datos, permisos, pruebas, releases o límites nativos.
- Compartir código donde el comportamiento de producto sea realmente común.
- Aislar integraciones nativas detrás de interfaces explícitas.
- No convertir Flutter en la arquitectura completa.
Manejo de errores y resiliencia
Las fallas esperadas incluyen red, validación, autenticación, backend, persistencia local y permisos. La arquitectura debe decidir qué se reintenta, qué tiene fallback, qué necesita mensaje de usuario y qué requiere diagnóstico.
- Evitar catches genéricos que esconden comportamiento.
- Diseñar mensajes de error como parte de la experiencia.
- Mantener contexto diagnóstico útil sin datos sensibles innecesarios.
Estrategia de pruebas
Las pruebas móviles funcionan mejor cuando el riesgo decide el nivel: unitarias, dominio, repositorios, integración, widgets/componentes, end-to-end y validación de release responden preguntas distintas.
- No probar todo desde la capa más lenta.
- Priorizar reglas, límites de integración y flujos críticos.
- Usar pruebas UI donde el riesgo de interacción sea real.
Release y entrega
Release móvil incluye variantes de build, ambientes, signing, configuración, CI/CD, canales, revisión de tienda, staged rollout, compatibilidad backend, feature flags y monitoreo posterior. Un rollback móvil no funciona como uno web.
- Planificar configuración y signing temprano.
- Coordinar backend con versiones instaladas.
- Usar Google Play como evidencia real de Bozz Apps sin afirmar App Store no verificado.
Observabilidad y diagnóstico
La observabilidad móvil debe capturar crashes, señales de rendimiento, red, versión, ambiente, contexto seguro y correlación con backend. El objetivo es entender fallas sin registrar datos sensibles innecesarios.
- Incluir versión y ambiente en diagnósticos.
- Conectar fallas móviles con comportamiento backend cuando sea posible.
- Mantener límites de privacidad explícitos.
Evolución y deuda técnica
Las apps evolucionan por dependencias, cambios de OS, SDKs, políticas de tienda, dispositivos antiguos, diseño, dominio, APIs, migraciones y features deprecadas. Reescribir todo rara vez es la primera respuesta.
- Detectar deriva arquitectónica antes de que sea comportamiento de producto.
- Actualizar dependencias considerando riesgo de release.
- Coordinar evolución móvil, backend y producto.
Cuándo no sobrearquitecturar
Una app pequeña con flujos simples, pocas pantallas, backend estable, baja complejidad, sin offline y vida corta no necesita cinco capas vacías. La simplicidad aún necesita límites, pruebas donde hay riesgo y manejo claro de errores.
- Usar arquitectura proporcional a la complejidad.
- Mantener apps simples legibles antes de agregar abstracciones.
- Agregar límites cuando cambio, riesgo o colaboración los justifiquen.
Principios
Mantener reglas fuera de la UI
Los workflows y validaciones importantes deben probarse sin renderizar pantallas ni depender de un framework.
- Mover reglas críticas fuera de widgets.
- Dejar que la UI orqueste, no que posea el dominio.
Hacer explícita la propiedad del estado
El estado se vuelve manejable cuando propiedad, ciclo de vida, invalidación y persistencia están nombrados.
- Separar estado local, servidor, dominio y persistido.
- Diseñar loading y errores con el mismo cuidado que el éxito.
Tratar fallas de conectividad como normales
Los usuarios móviles atraviesan redes inestables; los caminos de falla son parte del producto.
- Elegir offline-capable, offline-tolerant u offline-first deliberadamente.
- Mostrar recuperación y datos stale con claridad.
Separar transporte de dominio
Los payloads de API no deben dictar conceptos internos cuando el comportamiento necesita estabilidad.
- Mapear DTOs en límites.
- Mantener el lenguaje de dominio cerca de workflows, no de endpoints.
Aislar integraciones nativas
Las capacidades de plataforma deben quedar aisladas para que UI y dominio no dependan directamente de APIs del dispositivo.
- Encapsular permisos y platform channels.
- Probar comportamiento sin hardware cuando sea posible.
Probar donde existe riesgo de flujo
El nivel de prueba depende del costo de falla, no de un slogan de cobertura.
- Priorizar riesgo de dominio e integración.
- Usar end-to-end para rutas críticas.
Coordinar mobile y backend
Las versiones instaladas y los releases backend tienen ciclos distintos, por eso la compatibilidad debe planificarse.
- Versionar contratos cuando haga falta.
- Planificar releases considerando clientes antiguos.
Usar arquitectura proporcional
La buena arquitectura protege cambio y riesgo reales sin importar ceremonia de sistemas más grandes.
- Empezar simple si la complejidad es baja.
- Agregar capas cuando aclaren propiedad.
Decisiones arquitectónicas clave
Código compartido o específico por plataforma
Pregunta: ¿qué comportamiento debe compartirse y cuál debe ser nativo? Contexto: Flutter comparte UI y lógica, pero capacidades de plataforma pueden diferir. Trade-off: reutilización frente a ajuste nativo. Riesgo: forzar todo a compartido vuelve frágil lo nativo.
- Compartir comportamiento realmente común.
- Aislar integraciones específicas.
Propiedad del estado
Pregunta: ¿quién posee cada estado? Contexto: UI, dominio, servidor y persistencia cambian a ritmos distintos. Trade-off: simplicidad frente a ciclo de vida explícito. Riesgo: bugs por estado stale o duplicado.
- Nombrar dueños e invalidación.
- Evitar una sola bolsa global para todo.
Límites de dominio
Pregunta: ¿dónde viven las reglas de negocio? Trade-off: velocidad frente a testabilidad. Riesgo: reglas escondidas en pantallas difíciles de cambiar.
- Modelar las reglas que importan.
- Evitar DDD ceremonial en flujos triviales.
Fuente de verdad remota y local
Pregunta: ¿qué dato es autoritativo? Contexto: APIs, cachés y persistencia local pueden diferir. Trade-off: respuesta rápida frente a consistencia. Riesgo: usuarios actúan sobre datos conflictivos.
- Definir caché y sincronización.
- Explicar estados stale en UI.
Modelo de integración con APIs
Pregunta: ¿cómo conversa la app con backend? Contratos, errores, retries y versionado moldean confiabilidad. Riesgo: cambios backend rompen versiones instaladas.
- Traducir errores backend a estados de producto.
- Coordinar compatibilidad con releases.
Estrategia de autenticación y sesión
Pregunta: ¿cómo se manejan identidad, autorización y sesión? Tokens expiran, acceso se revoca y permisos cambian. Riesgo: usuarios quedan en estados inválidos.
- Separar login, roles y permisos del dispositivo.
- Manejar expiración explícitamente.
Estrategia offline
Pregunta: ¿la app será offline-capable, offline-tolerant u offline-first? Trade-off: resiliencia frente a complejidad de sync. Riesgo: cambios locales entran en conflicto o desaparecen.
- Diseñar retries y conflictos.
- No agregar offline-first sin necesidad real.
Release y observabilidad
Pregunta: ¿cómo se publican, monitorean y diagnostican versiones? Store review y staged rollout difieren de web. Riesgo: fallas descubiertas tarde sin rollback claro.
- Rastrear versión y ambiente.
- Planificar compatibilidad con instalaciones existentes.
Perspectivas futuras en desarrollo
Estos temas están planificados bajo el hub de arquitectura móvil. Todavía no son rutas públicas.
- El manejo de estado no es arquitectura móvil.
- Aplicaciones offline-capable versus offline-first.
- Cómo separar lógica de dominio de UI Flutter.
- Patrones repository sin abstracción innecesaria.
- Cómo coordinar releases móviles y backend.
- Pruebas de workflows móviles en el nivel correcto.