Cuando comenzamos a aprender Flutter lo primero que nos llama la atención, sobre todo a los viejos del barrio como yo, es que no hay una forma clara o predefinida por parte de Google de ordenar las cosas dentro de un proyecto Flutter.
Se limitan a decir que dentro de la carpeta lib va tu código y ¡ya! o como mucho, he visto que a veces van un poco mas allá y te dicen que pongas una carpeta src dentro de la carpeta lib y ahí pones tu código. No sé a vosotros, pero esto a mí me mata un poco. Necesito poner orden y este es el motivo de este post.
En este post, describiré mi forma (o una forma) de ordenar el código en nuestros proyectos de Flutter. Como ya digo, es mi sugerencia y para nada está escrita en piedra, por lo que cualquier aportación o sugerencia será bienvenida.
Con Xamarin y Microsoft no tenía esta sensación de «descontrol», dado que la mayoría de los ejemplos aportados en la documentación de Microsoft, llevan el mismo patrón a la hora de ordenar nuestro código dentro del proyecto. Aún así y supongo que, debido a la experiencia, incluso en los últimos proyectos con Xamarin los ordenábamos de una forma un poco distinta a la que propone la misma Microsoft en su documentación.
Partiendo de esta experiencia previa, la ordenación que me gusta seguir en los proyectos de Flutter (y antes en los de Xamarin) es una ordenación basada en la funcionalidad o lógica en lugar de en tipos. Este tipo de estructura u ordenación nos facilita la reutilización y la modularidad del código, por lo tanto se adapta mejor a los cambios, ya que podemos tener módulos independientes que pueden identificarse y modificarse sin necesidad de tocar el resto de funcionalidades. Además, ayuda a tener un árbol de la solución mucho menos vertical y más legible entre otras ventajas.
De esta forma, para mí la estrucutra de un proyecto en Flutter quedaría de la siguiente manera
- Partimos de la carpeta lib y en ella ya pondremos todo nuestro código.
- La carpeta bases será para todas nuestras clases base de las que heredaran el resto de las clases si las tenemos.
- La carpeta commons contendrá todas aquellas clases con configuraciones comunes a toda la aplicación, normalmente son clases estáticas con cadenas de configuración, por ejemplo commons/settings_keys.dart
- La carpeta enums tendrá todos los enumerados comunes de nuestra aplicación.
- La carpeta models tendrá todos los modelos comunes de nuestra aplicación.
- La carpeta features. Esta puede que sea la carpeta más importante. La idea es que aquí estén las funcionalidades de nuestra aplicación, es decir, si nuestra aplicación usa un login, habrá una carpeta para el login (features/login). Si existe un perfil de usuario, habrá una carpeta para nuestra pantalla de perfil de usuario (features/profile) etc. Cada carpeta contendrá lo necesario para esa funcionalidad. Si existe un enumerado, un modelo o un servicio que sólo utiliza está funcionalidad de nuestra aplicación, estará aquí. Pero no estarán de cualquier forma, sino que respetarán la ordenación en carpetas que estamos viendo. Es decir, features puede tener dentro una carpeta models, que tendrá los modelos que sólo utiliza esa funcionalidad, por ejemplo features/login/models.
- La carpeta providers. En los proyectos de Flutter actualmente estoy haciendo uso de Providers y me gusta colocar aquí los providers que son comunes a toda la aplicación. Si hubiese un provider que solo se utiliza en una funcionaldiad, estaría dentro de la carpeta features y la carpeta correspondiente a la funcionalidad. Por ejemplo, aquí encontraríamos el provider para la s settings de usuario que afectan a toda la aplicación.
- La carpeta widgets viene a ser algo así como la carpeta controls. Aún no tengo claro si llamarla controls o widgets, en principio la he dejado widgets para indicar que son widgets genéricos que se utilizan a lo largo de la aplicación. Pero podría ser controls perfectamente.
- La carpeta themes contendrá toda la configuración relacionada con el tema de colores que utilice nuestra aplicación.
- La carpeta routes es donde defino la clase con las rutas para la navegación dentro de la aplicación
- La carpeta i18N es donde vamos a añadir las cadenas de texto localizadas en los idiomas que necesitemos que nuestra aplicación esté.
- La carpeta services contendrá los servicios que sean genéricos, como el servicio de si hay conexión o el servicio para preservar los datos en local etc..
Básicamente esta sería la estructura básica que creo cuando inicio un proyecto en Flutter y que me ayuda a mantener todas las clases ordenadas y así facilitar el mantenimiento del proyecto a corto y largo plazo.
Cómo nota, para simplificar los imports en los archivos que pueden llegar a crecer mucho con esta organización en carpetas, suelo utilizar lo que llaman un barrel file dentro de cada carpeta, así la carpeta providers, tentrá un barrel file providers.dart que exporta lo necesario a otras clases, providers/providers.dart.
¿Qué opinas de esta ordenación? ¿usarías la misma? ¿qué cambiarías? Estaría bien discutirlo y llegar a la mejor ordenación posible 🙂