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.

Presentación y navegación

Presentación incluye UI, navegación, composición de pantallas, estado visual, componentes reutilizables, accesibilidad, comportamiento adaptativo, deep links y routing. Debe expresar intención de usuario sin absorber reglas de negocio.

  • No convertir widgets o views en entidades de dominio.
  • Hacer visibles las decisiones de navegación en autenticación, onboarding y permisos.
  • Tratar accesibilidad y adaptación como comportamiento de producto.

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.

¿Necesitas aplicar arquitectura móvil a una app real?

Usa este hub para revisar decisiones. Usa el servicio cuando el siguiente paso es alcance, arquitectura, implementación o preparación de release.

Ver servicio móvil