💡Flutter Leap Monolito
O Flutter Leap, é um repositório base que mantemos, contendo a arquitetura de pastas propostas para os nossos projetos, os plugins que utilizamos com frequência, alguns componentes e funcionalidades.
Architecture overview
Temos aqui uma imagem explicando através de um diagrama o uso da arquitetura que temos atualmente no nosso projeto leap, desde a separação de pastas e lógica, conexão com API e a build de CI/CD.

Aqui vou descrever um pouco os arquivos existentes, padrões que vamo seguir, etc:

Dentro da pasta APP, vamos sempre ter um arquivo app_module. Ele vai ser o responsável por definir todos os módulos da aplicação, realizar o roteamento e injeção de dependências de cada módulo, da seguinte maneira:
APP MODULE (quem comanda a aplicação)
Cada módulo novo que criarmos, tem de seguir um padrão de arquivos também, fora a parte de domain, infra e presenter, todo módulo vai conter um arquivo "nome_do_module_module.dart", o qual vai sempre implementar do DefaultModule.
Essa classe do módulo, é quem vai ter as definições de quais são as rotas e as dependências desse módulo, das seguinte maneira:
MÓDULO INDIVIDUAL (cada feature do projeto)
O HomeModule tem de implementar de DefaultModule, para garantir que vai ter as funções de rotas e dependencias, sendo necessário também a criação de um HomeRouteModule que implementa do RouteModule, para garantir o formato correto de definição de rotas para o módulo.
Obs: Esse padrão deve ser seguido para todos os módulos subsequentes criados na aplicação.
INJEÇÃO DE DEPENDÊNCIA (desacoplada na aplicação)
É possível visualizar que a função de registrar dependência nos módulos, recebe como parâmetro uma classa abstrata IDependencyInjector, para ser possível serem feitas alterações sem mexer no módulo, caso necessário.
O conteúdo de IDependencyInjector, possui as funções para registrar as dependências:
Nesse caso, podemos criar classes com qualquer tecnologia para injetar as dependencias, desde que elas implementem essa interface. Exemplo com GET IT:
E onde isso vai ser utilizado? Na nossa main!
MAIN DO PROJETO
Na main do projeto, temos alteração em 2 pontos: rotas e injeção de dependencia. A injeção para de ser em um arquivo setupGetIt, e passa a ser feita pelo AppModule mostrado anteriormente, da seguinte maneira:
E aqui que passamos a implementação do GetItInjector, e caso desejamos usar outro injetor, é aqui apenas onde a alteração precisa ser feita.
E no materialApp, o roteamento é da seguinte maneira:
Assim, todas as rotas do projeto são manipuladas pelo AppModule, que pega as rotas de todos os módulos registrados.
Descrição técnica
O projeto é estruturado seguindo um modelo de Clean Arch e os princípios do SOLID, utilizando se de uma modularização focada em reutilização.
Camada BASE: Composta por dois segmentos, 'APP' para o núcleo funcional do aplicativo e 'SHARED' para recursos utilizáveis por múltiplos módulos, promovendo a reutilização de código e consistência em todo o aplicativo.
Camada MODULES: Enfatiza a modularidade, permitindo a expansão e manutenção independentes de cada módulo. 'EXAMPLE_MODULE' é destacado para exemplificar a estrutura interna de um módulo.
Dentro de EXAMPLE_MODULE:
Presenter: Encarrega-se da lógica de apresentação. 'COMPONENTS' são elementos reutilizáveis da UI, 'PAGES' representam telas compostas por esses componentes, e 'STORES' gerenciam o estado, facilitando a reatividade e o gerenciamento de estado local.
Domain: Define as regras de negócio. 'REPOSITORIES INTERFACES' e 'USECASES INTERFACES' estabelecem contratos claros para a lógica de negócios, enquanto 'USECASES IMPLEMENTATION' contém a lógica de negócio executável e 'ENTITIES' são as abstrações de alto nível dos objetos de domínio.
Infra: 'DATASOURCES' implementam os contratos dos repositórios e são responsáveis pela comunicação com fontes de dados externas e internas, interagindo diretamente com 'MODELS', que são representações de dados ajustados para serem usados na camada de infraestrutura.
Na base do diagrama, recursos como 'API', 'Http requests', 'Flutter Secure Storage' e 'Local Storage' são identificados como pontos de integração e persistência de dados, fundamentais para operações de I/O.
Finalmente, um pipeline de CI/CD é representado, indicando a automatização dos processos de compilação, teste e distribuição do aplicativo para as plataformas 'App Store' e 'Google Play', assegurando a entrega contínua de valor ao usuário final com qualidade e eficiência.
A injeção de dependências acontece utilizando o plugin que desejar, desde que haja uma implementação dele seguindo a interface IDependencyInjector . Dentro da pasta injector (Dentro de "SHARED") podemos criar a implementação desejada. Quem vai tratar a injeção de fato posteriormente é o AppModule, módulo principal que registra todos os submodulos. Portanto, se uma tela precisa de um dado da API, o seguinte fluxo deve ser feito: a assinatura desta chamada deve ser escrita em algum repositório; a implementação desta função deve ser feita no respectivo datasource; uma interface de usecase e sua implementação devem ser criados; a tela deve ser criada; esta tela precisa depender de uma store; na store devem ser feitos as actions e observables para utilizar o usecase.
Essa arquitetura escolhida foi baseada na arquitetura Clean Dart proposta para o Flutter. Ela foi a inspiração, mas foram feitas alterações de acordo com as necessidades e entendimentos próprios.
Você pode encontrara documentação da Clean Dart aqui: https://github.com/Flutterando/Clean-Dart
Veja como melhorar a produtividade ao criar novos módulos em:
🧱Mason - Generate ModulesLast updated