Flutter — Creando un Proyecto Repetitivo perfecto desde cero

Crédito: Nguyễn Thành Minh (desarrollador de Android)
Todos hemos estado allí, lo que quiero decir es que todos hemos tratado de construir un proyecto repetitivo, ya sea para el trabajo o como un proyecto personal. Un buen proyecto repetitivo nos ahorrará mucho tiempo al resolver problemas comunes como llamar a API, procesar datos de bases de datos y, quizás lo más importante, hacer que nuestro código sea organizado y coherente para que las personas puedan tener más facilidad para entender nuestro código. Esta serie pretende compartir un proyecto repetitivo que he construido, usado y mantenido durante los últimos dos años. No solo eso, compartiré mi enfoque para codificarlo, así como soluciones a problemas comunes que puedan surgir. Dicho esto, esta es la parte 1: Explorando el Proyecto.
Ver en Github

1. Características
Características construidas en este proyecto:
- Arquitectura: Arquitectura Limpia
- Gestión de estado: flutter_bloc
- Navegación: auto_ruta
- DI: get_it , inyectable
- API REST: dio
- GraphQL: artemisa , graphql_flutter
- Base de datos: caja de objetos
- Preferencias compartidas: crypted_shared_preferences
- Clase de datos: congelado
- Pelusa: dart_code_metrics , flutter_lints
- CI/CD: acciones de Github, canalizaciones de Bitbucket
- Prueba unitaria: mocktail , block_test
- Paginación: infinite_scroll_pagination
- Utilidades : rxdart , dartx , async
- Generador de activos: flutter_gen_runner , flutter_launcher_icons , flutter_native_splash
- Otras características: reintento automático de solicitudes de API fallidas, token de actualización,...
Para ejecutar este proyecto según lo previsto, la versión de Flutter debe ser (exactamente) 3.3.9 y la versión 2.8.0 de Melos debe estar instalada. Si desea tener una convención de Git para su equipo, también puede instalar lefthook . Hablaré sobre Melos y Lefthook en las últimas partes de la serie. Por ahora, así es como se ejecuta el proyecto.
Nota: utilicé VSCode y macOS, por lo que no puedo garantizar que también funcione en Android Studio o Windows.
2.1. Instalando Melos
Clean Architecture requiere que dividamos el proyecto en múltiples módulos (paquetes), por lo que necesitamos una herramienta para administrar paquetes: Melos. Para instalar Melos:
dart pub global activate melos 2.8.0
export PATH="$PATH:<path to flutter>/flutter/bin"
export PATH="$PATH:<path to flutter>/flutter/bin/cache/dart-sdk/bin"
export PATH="$PATH:~/.pub-cache/bin"
Después de instalar Melos, deberá ejecutar el comando make gen_env
o dart run tools/gen_env.dart
. Esta es una herramienta que creé yo mismo, para crear la env
carpeta para que podamos declarar secretos como Google API_KEY, credenciales de autenticación básicas, etc. Esta herramienta leerá los valores en el .env
archivo y luego los colocará en la dart-define
bandera cuando la aplicación Flutter esté correr o construir.

2.3. Generación de archivos
Una vez que tenemos la env
carpeta, ahora solo necesitamos ejecutar el comando make sync
. Esta es una abreviatura de tres comandos:
melos bootstrap
melos run l10n
melos run force_build_all
A continuación, el comando melos run l10n
ayuda a generar la clase S
a partir de los .arb
archivos de los resources
módulos.

Finalmente, el comando melos run force_build_all
ayuda a generar los archivos .g.dart
, .freezed.dart
etc. en todos los paquetes que tiene la biblioteca build_runner
.
¡ Ahora, corre make run_dev
para ejecutar la aplicación y disfruta!
3. Proyecto de Arquitectura
En total, tenemos 6 módulos (paquetes)
- aplicación
- Dominio
- Datos
- Recursos
- Compartido
- Inicializador
3.1. El módulo de la aplicación
Aquí es donde codificaremos nuestra UI y Bloc. Además, es donde almacenaremos nuestros recursos como colores, dimensiones y estilos de texto. Aquí es también donde declararemos nuestra función main() como punto de entrada para que se ejecute nuestra aplicación.

Ambas carpetas app_icon
y splash
contienen los archivos app-icon.yaml
, splash.yaml
por lo que podemos configurar el ícono de la aplicación y la pantalla de inicio según las instrucciones de las bibliotecas flutter_launcher_icons y flutter_native_splash .
La app
carpeta contiene AppBloc
, que es un bloque provisto en MaterialApp
, un lugar desde donde todas las pantallas de la aplicación pueden recuperar datos, en otras palabras; es como un Bloc compartido a todas las pantallas. Puede usarlo AppBloc
para tareas que necesitan actualizar la interfaz de usuario de todas las pantallas, como la configuración de idioma, el cambio de modo oscuro/modo claro.
La carpeta es donde codificaremos clases base base
como BasePageState
, BaseBloc
y .BaseEvent
BaseState
La carpeta shared_view
es donde codificaré la interfaz de usuario compartida entre muchas pantallas, y luego se puede usar para otros proyectos. Por ejemplo: app_text_field
, circle_image
son vistas de grupo comunes que se ven en las pantallas de inicio de sesión y registro.
La carpeta common_view
es donde codificaré la interfaz de usuario compartida entre muchas pantallas, y luego se puede usar para otros proyectos. Por ejemplo, common_dialog
, common_app_bar
, common_scaffold
se puede reutilizar en muchos proyectos, aunque es posible que queramos ajustarlos un poco para que coincidan con el estilo.
La carpeta config
es donde llamaré a las funciones de configuración para el módulo de la aplicación, comoFirebase.initializeApp()
La carpeta di
es para la configuración de DI para el módulo de la aplicación.
La carpeta exception_handler
se encargará de todas las excepciones en el proyecto.
La carpeta helper
contiene clases auxiliares utilizadas exclusivamente para el módulo de la aplicación.
La carpeta navigation
es donde declararemos las pantallas, así como los cuadros de diálogo y las hojas inferiores utilizadas en la aplicación.
La carpeta resource
es donde declararemos recursos para la interfaz de usuario, como colores, dimensiones y estilos de texto.
La carpeta ui
es donde codificaré la interfaz de usuario y el bloque para cada pantalla.
La carpeta utils
es donde codificaré las funciones de utilidades utilizadas exclusivamente para el módulo de la aplicación.
3.2. El módulo de dominio

Al igual que el módulo de la aplicación, las carpetas config
y di
tienen propósitos similares en el módulo de dominio.
La carpeta entity
contiene entidades de clase como Usuario y Reserva.
La carpeta navigation
tiene la AppNavigator
clase, que es responsable de push
, replace
y pop
de las pantallas.
La carpeta repository
es donde declararemos las clases del repositorio abstracto en el proyecto.
La carpeta usecase
es donde declararemos los casos de uso en el proyecto.
3.3. El módulo de datos

Del mismo modo, las carpetas config
y di
tienen el mismo propósito aquí.
La carpeta graphql
contiene .graphql
y schema.graphql
si su proyecto usa GraphQL. El archivo build.yaml
se usa para configurar los archivos generados que están relacionados con GraphQL.
La carpeta repository
contiene clases de implementación de repositorio. También contiene varias carpetas:
converter
: para codificar clases de convertidormapper
: para codificar clases de mapeador que luego se utilizan para mapear modelos de datos en entidadesmodel
: para codificar clases de modelos de datossource
: para codificar clases base como RestApiClient, GraphQlApiClient y proporcionar fuentes de datos en el proyecto como AppApiService, AppDatabase, AppSharedPreferences, LocationDataSource

Este es un módulo simple, solo contiene .arb
archivos que proporcionan cadenas para la localización. Este módulo se inyecta en otros dos módulos, app
por domain
lo que las clases UI, Bloc, Entity y Use Case pueden usarlo.
3.5. El módulo compartido

Como sugiere el nombre, este módulo proporciona constantes, clases de excepción personalizadas, clases de ayuda, mixins y funciones utils para que las usen otros módulos.
3.6. El módulo inicializador

Este módulo solo contiene la clase AppInitializer. Esta clase es responsable de reunir todas las configuraciones de otros módulos en una init()
función; La main()
función solo tiene que llamar a esta init()
función para recuperar todas las configuraciones de todos los módulos.
3.7. Otras carpetas y archivos
La carpeta .github
es para configurar CI/CD si su proyecto usa Github Actions.
La carpeta .lefthook
y el archivo lefthook.yml
son para configurar la convención de Git usando la biblioteca de gancho izquierdo.
La carpeta .vscode
es para declarar la configuración de VSCode utilizada para este proyecto.
La carpeta .env
es para declarar secretos para cada entorno.
La carpeta tools
contiene herramientas que he creado.
El archivo analysis_options.yaml
es para declarar las reglas de linter de dos bibliotecas, flutter_lints y dart_code_metrics .
El archivo bitbucket-pipelines.yml
es para configurar CI si su proyecto usa Bitbucket Pipelines.
El archivo makefile
realiza un seguimiento de todos los comandos utilizados en el proyecto. Por ejemplo, el comando make format
ayuda a formatear todo el código con .dart
extensión de archivo dentro del proyecto. Hay muchos más comandos como make test
el que ejecuta Unit Test en todos los módulos.
El archivo melos.yaml
es para configurar Melos.
Conclusión
¿Por qué necesitamos crear otro módulo solo para la configuración de inicio? ¿Qué son las clases de mapeador, entidad y caso de uso? Los repasaré en la segunda parte de esta serie: la arquitectura limpia.