💡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-Dartarrow-up-right

Veja como melhorar a produtividade ao criar novos módulos em:

🧱Mason - Generate Moduleschevron-right

Last updated