Esta es la primera publicación de una serie de publicaciones que explican mi comprensión de la arquitectura de aplicaciones de Flutter. Te lo advierto: será muy seguro de ti mismo .
Hasta ahora planeado:
Prólogo
He estado en programación durante unos 20 años. Comencé el desarrollo móvil hace 4 años con Xamarin.Forms, porque multiplataforma fue la única motivación para mí como desarrollador independiente. Xamarin.Forms literalmente lo empuja a usar el patrón MVVM, ya que la interfaz de usuario está definida en XAML, y necesita algún tipo de capa para pegar la interfaz de usuario con el modelo. En el proceso de trabajar con Xamarin, conocí a ReactiveUI y me cautivaron literalmente las transmisiones y las extensiones reactivas ( Rx ) que hicieron que mis aplicaciones fueran más confiables.
Si bien los MVVM de Xamarin.Forms estaban listos para usar, cuando cambié a Flutter, me sorprendió que no hubiera patrones de diseño similares. Comencé a investigar los diversos enfoques propuestos, pero ninguno de los disponibles me satisfizo por completo:
- InheritedWidget : no pude actualizar solo la parte modificada del árbol de widgets, así que lo usé solo para acceder a las clases de modelos que publican secuencias de dardos (Dart Streams), pero pronto abandoné esta idea en favor de la plantilla Localizador de servicios
- El modelo con alcance es más interesante que el
InheritedWidget
, pero no me dio tanta flexibilidad como estaba acostumbrado con ReactiveUI - Redux fue la plantilla recomendada por muchos desarrolladores familiarizados con React Native. Tengo una publicación completa sobre por qué no me gusta.
- BLoC : si aún no hubiera comenzado a desarrollar mi propio patrón en un momento en que BLoC comenzó a avanzar, lo más probable es que lo hubiera tomado, ya que es realmente flexible y reactivo. Lo que no me gusta es que publica Stream Sinks y no puedo simplemente tomar y pasar funciones o comandos al controlador de eventos del widget. Además, BLoC no le dice cómo estructurar su aplicación como un todo, ni hay una definición clara de qué tan grande debe ser un determinado BLoC o cuál es su alcance
- MVVM : desde que trabajé con él, esto es lo primero que esperaba implementar en Flutter. Pero no! El punto de ViewModel es proporcionar con gracia la representación de su modelo en Ver a través de enlaces. Pero Flutter no actualiza sus modelos con nuevos datos, siempre los reconstruye, como ya describí . Además, ViewModels siempre debe estar sincronizado con el modelo base, lo que conduce a errores desagradables, y la realidad muestra que la ventaja prometida de reutilizar ViewModels en las aplicaciones casi nunca se logra. Adam Pedley tiene una gran publicación sobre estos defectos
La cruda verdad sobre la redundancia de capas
Es casi un dogma la idea de que en el desarrollo siempre debe construir su aplicación en varias capas, cada una de las cuales tiene acceso solo al subyacente, ya que esto le permitirá:
- reutilizar capas en otros proyectos
- reemplazar transparentemente una capa con otra
- simplificar las pruebas
Sin embargo:
- En mi práctica, no había ningún caso en el que observara una reutilización completa de capas. Si tiene un código universal que se puede reutilizar, tiene más sentido ponerlo en algún tipo de biblioteca universal;
- reemplazar capas enteras tampoco es una práctica común. Es poco probable que la mayoría de las personas reemplace la base de datos después de que la aplicación haya alcanzado una determinada etapa de desarrollo, entonces, ¿por qué agregarle una capa de abstracción? Bueno, si se requieren algunas de nuestras herramientas de desarrollo actuales, la refactorización es bastante fácil;
- lo que realmente funciona es la simplificación de las pruebas
Sin embargo, no estoy en contra del uso de capas si debemos seguir esta regla tan imprudentemente como antes. El uso excesivo de ellos conduce a un aumento en el código y potencialmente puede crear problemas mientras se mantiene una sola fuente de estado de la aplicación. Por lo tanto, aplique capas cuando sea realmente necesario y no se base en "mejores prácticas".
Arquitectura ideal para Flutter
Entonces, ¿qué espero de una arquitectura perfecta?
- Facilidad de comprensión de la aplicación. Para mí, este es el objetivo más importante. Los nuevos desarrolladores involucrados en el trabajo con código existente deberían comprender fácilmente la estructura de desarrollo
- Facilidad de desarrollo de equipo
- La arquitectura en sí debería ser fácil de entender y mantener.
- No hay código de plantilla para muletas en desarrollo
- Aleteo de soporte de estilo reactivo
- Depuración fácil
- El rendimiento no debería sufrir
- Facilidad de expansión
- Facilidad de prueba
- Oportunidades para centrarse en la aplicación en lugar de deambular por la fuente
Independencia del widget
Según la naturaleza de los elementos de interfaz sin estado, ninguna página / widget en Flutter debería depender de otros ni influir en ellos. Esto lleva a la idea de que cada página / widget debería ser responsable de forma independiente de mostrarse y todas sus interacciones con el usuario.
Rxvms
RxVMS es una evolución del patrón RxVAMS descrito en una publicación anterior , durante la aplicación práctica de la cual se identificaron y solucionaron algunos problemas.
El resultado actual de todos estos pensamientos es el patrón RxVMS o Rx-View-Managers-Services. Realiza todas las tareas anteriores con el único requisito de que debe comprender los hilos y elementos Rx. Para ayudarte con esto, te dedico la siguiente publicación.
Aquí hay un breve resumen de mi solicitud

Servicios
Estas son abstracciones de interfaces con el mundo exterior, que pueden servir como bases de datos, API REST, etc. No afectan el estado de la aplicación.
Gerentes
Los administradores agrupan funcionalidades semánticamente similares, como autenticación, procedimientos de pedido y similares. Los gerentes manipulan el estado de un objeto.
Cualquier cambio de estado (cambios en los datos de la aplicación) debe hacerse solo a través de los administradores. Como regla general, los propios administradores no almacenan datos, excepto en casos críticos para el rendimiento o las constantes de tiempo de ejecución.
Los gerentes pueden servir como fuentes de datos proxy, en caso de que se requiera cierta transformación después de una solicitud de los servicios. Un ejemplo es combinar datos de dos o más fuentes para mostrar en una vista.
Los gerentes pueden interactuar entre ellos.
Vistas
Por lo general, se trata de StatefullWidget o StreamBuilder, que puede usar datos de administradores y servicios. Puede ser una página completa o un widget. Las vistas no almacenan ningún estado y pueden comunicarse directamente con los servicios mientras se respeta esta regla.
Objetos de dominio
Aunque no se incluye en el diagrama, estas son entidades importantes que representan el modelo de negocio. En otros patrones, pueden pertenecer a una capa separada ( modelo de negocio ) junto con la lógica de negocios. Aquí, en RxVMS, no contienen ninguna lógica que cambie el estado de la aplicación. Casi siempre, estos son tipos de datos simples: objetos de datos simples (si los incluyera en el patrón, se vería como RxVMMS, que es un poco largo y genera confusión: la VM podría confundirse con un ViewModel). Lógicamente, los objetos de dominio se encuentran en la capa de administradores.
Las siguientes publicaciones revelarán la esencia y la interacción de estos elementos.