Conceptos comunes de arquitectura
Aprende sobre conceptos comunes de arquitectura en el diseño de aplicaciones y cómo se aplican a Flutter.
En esta sección, encontrarás principios probados y verdaderos que guían las decisiones arquitectónicas en el mundo más amplio del desarrollo de aplicaciones, así como información sobre cómo se adaptan específicamente a Flutter. Es una introducción sencilla al vocabulario y conceptos relacionados con la arquitectura recomendada y las mejores prácticas, para que puedan explorarse con más detalle a lo largo de esta guía.
Separación de conceptos
#La separación de responsabilidades es un principio fundamental en el desarrollo de aplicaciones que promueve la modularidad y la mantenibilidad al dividir la funcionalidad de una aplicación en unidades distintas e independientes. A grandes rasgos, esto significa separar la lógica de la UI de la lógica de negocio. Esto a menudo se describe como arquitectura en capas. Dentro de cada capa, deberías separar aún más tu aplicación por funcionalidad o característica. Por ejemplo, la lógica de autenticación de tu aplicación debería estar en una clase diferente a la lógica de búsqueda.
En Flutter, esto también se aplica a los widgetsWidgetEl bloque de construcción básico de una interfaz de usuario de Flutter. Aprende más en la capa de UI. Deberías escribir widgets reutilizables y ligeros que contengan la menor lógica posible.
Arquitectura en capas
#Las aplicaciones Flutter deberían escribirse en capas. La arquitectura en capas es un patrón de diseño de software que organiza una aplicación en capas distintas, cada una con roles y responsabilidades específicos. Normalmente, las aplicaciones se separan en 2 o 3 capas, dependiendo de la complejidad.
- Capa de UI: Muestra datos al usuario expuestos por la capa de lógica de negocio y maneja la interacción del usuario. También se le conoce comúnmente como la "capa de presentación".
- Capa de lógica: Implementa la lógica de negocio central y facilita la interacción entre la capa de datos y la capa de UI. Comúnmente conocida como la "capa de dominio". La capa de lógica es opcional y solo necesita implementarse si tu aplicación tiene una lógica de negocio compleja que ocurre en el cliente. Muchas aplicaciones solo se preocupan por presentar datos a un usuario y permitirle cambiar esos datos (coloquialmente conocidas como aplicaciones CRUD). Es posible que estas aplicaciones no necesiten esta capa opcional.
- Capa de datos: Gestiona las interacciones con las fuentes de datos, como bases de datos o plugins de plataforma. Expone datos y métodos a la capa de lógica de negocio.
Se llaman "capas" porque cada capa solo puede comunicarse con las capas directamente debajo o encima de ella. La capa de UI no debería saber que existe la capa de datos, y viceversa.
Única fuente de verdad
#Cada tipo de datos en tu aplicación debería tener una única fuente de verdad (SSOT). La fuente de verdad es responsable de representar el State local o remoto. Si los datos se pueden modificar en la aplicación, la clase SSOT debería ser la única clase que pueda hacerlo.
Esto puede reducir drásticamente el número de errores en tu aplicación y simplificar el código, ya que solo tendrás una única copia de los mismos datos.
Generalmente, la fuente de verdad para cualquier tipo de datos en tu aplicación se mantiene en una clase llamada Repository, la cual forma parte de la capa de datos. Normalmente hay una clase repositorio para cada tipo de datos en tu aplicación.
Este principio se puede aplicar a través de capas y componentes en tu aplicación así como dentro de clases individuales. Por ejemplo, una clase Dart podría usar getters para derivar valores de un campo SSOT (en lugar de tener múltiples campos que deban actualizarse de forma independiente) o una lista de records para agrupar valores relacionados (en lugar de listas paralelas cuyos índices podrían desincronizarse).
Flujo de datos unidireccional
#El flujo de datos unidireccional (UDF) se refiere a un patrón de diseño que ayuda a desacoplar el State de la UI que lo muestra. En los términos más sencillos, el State fluye desde la capa de datos a través de la capa de lógica y, finalmente, a los widgets en la capa de UI. Los eventos de la interacción del usuario fluyen en la dirección opuesta, desde la capa de presentación, regresando a través de la capa de lógica hasta la capa de datos.
En el UDF, el ciclo de actualización desde la interacción del usuario hasta la renderización de la UI se ve así:
- [Capa de UI] Ocurre un evento debido a la interacción del usuario, como hacer clic en un botón. La función callback del manejador de eventos del widget invoca un método expuesto por una clase en la capa de lógica.
- [Capa de lógica] La clase de lógica llama a métodos expuestos por un repositorio que saben cómo mutar los datos.
- [Capa de datos] El repositorio actualiza los datos (si es necesario) y luego proporciona los nuevos datos a la clase de lógica.
- [Capa de lógica] La clase de lógica guarda su nuevo State, el cual envía a la UI.
- [Capa de UI] La UI muestra el nuevo State del view model.
Los nuevos datos también pueden comenzar en la capa de datos. Por ejemplo, un repositorio podría sondear un servidor HTTP para buscar nuevos datos. En este caso, el flujo de datos solo realiza la segunda mitad del viaje. La idea más importante es que los cambios de datos siempre ocurren en la SSOT, que es la capa de datos. Esto hace que tu código sea más fácil de entender, menos propenso a errores y evita que se creen datos mal formados o inesperados.
La UI es una función del State (inmutable)
#Flutter es declarativo, lo que significa que construye su UI para reflejar el State actual de tu aplicación. Cuando el State cambia, tu aplicación debería desencadenar una reconstrucción de la UI que depende de ese State. En Flutter, a menudo escucharás que esto se describe como "la UI es una función del State".
Es fundamental que tus datos impulsen tu UI, y no al revés. Los datos deberían ser inmutables y persistentes, y las views deberían contener la menor lógica posible. Esto minimiza la posibilidad de que se pierdan datos al cerrar la aplicación, y hace que tu aplicación sea más fácil de probar y más resistente a los errores.
Extensibilidad
#Cada pieza de la arquitectura debería tener una lista bien definida de entradas y salidas. Por ejemplo, un view model en la capa de lógica solo debería tomar fuentes de datos como entradas, como repositorios, y solo debería exponer comandos y datos formateados para las views.
El uso de interfaces limpias de esta manera te permite reemplazar las implementaciones concretas de tus clases sin necesidad de cambiar nada del código que consume la interfaz.
Testeabilidad
#Los principios que hacen que el software sea extensible también facilitan sus pruebas. Por ejemplo, puedes probar la lógica independiente de un view model simulando un repositorio. Las pruebas del view model no requieren que simules otras partes de tu aplicación, y puedes probar tu lógica de UI de forma independiente de los propios widgets de Flutter.
Tu aplicación también será más flexible. Será sencillo y de bajo riesgo añadir nueva lógica y nueva UI. Por ejemplo, añadir un nuevo view model no puede romper ninguna lógica de las capas de datos o de lógica de negocio.
La siguiente sección explica la idea de entradas y salidas para cualquier componente dado en la arquitectura de tu aplicación.
Comentarios
#Dado que esta sección del sitio web está evolucionando, ¡agradecemos tus comentarios!
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-11. Ver código fuente oreportar un problema.