Microapps architecture com Dart/Flutter

Microapps architecture com Dart/Flutter

Photo by Raphael Koh on Unsplash

A arquitetura de microapps tem como objetivo proporcionar ao usuário uma experiência unificada, utilizando diversos microapps altamente especializados.

Com Flutter/Dart, temos a oportunidade ideal para criar projetos com essa arquitetura, devido à comunidade madura e ao excelente sistema de gerenciamento de pacotes e dependências disponível.

Modularizar 🧩

Ao pensar em microapps, é importante modularizar e especializar partes de um aplicativo maior. Para agilizar o desenvolvimento, é necessário buscar ferramentas que possam ajudar nesse processo.

Uma opção para modularização é o Flutter Modular, que é amplamente conhecido e robusto. Ele permite a modularização e oferece um sistema de Injeção de Dependência (DI) interessante, sem que seja necessário se preocupar com rotas. Outra opção é o Module Provider, que também é bastante robusto e ajuda a modularizar, a utilizar DI e a navegar entre as telas.

Mesmo que existam esses e outros pacotes para ajudar na modularização, em muitas situações pode ser necessário criar nossa própria solução para alcançar esse objetivo. Eu mesmo já gastei algumas horas desenvolvendo algo semelhante ao Flutter Modular e ao Module Provider, construindo uma fachada para o Go_router e um sistema de DI semelhante ao Kiwi ou ao Get_it (que, sim, funcionou! 🤣).

Vários microapps, um build 🔗

Ao contrário da arquitetura de micro serviços, a arquitetura de microapps muitas vezes requer que vários microapps sejam agregados em um único super app, que pode ser construido e distribuido em um único arquivo. Para isso, pode ser necessário ter um projeto ou pacote que sirva como "cola", contendo todas as dependências dos microapps e serviços e, talvez, inicializando o MaterialApp e outras configurações comuns no "void main()".

Com essa abordagem, é possível versionar cada microapp e distribuí-los para diferentes equipes que cuidam de contextos diferentes. Onde trabalho hoje, optamos por um projeto monorepo e gerenciamos as versões usando tags no Git, mas estamos avaliando se precisamos criar um pub.dev personalizado (como o https://pub.dev/packages/unpub ou jFrog, por exemplo) para nossas necessidades específicas.

Uma vantagem de versionar seus microapps é que um rollback seria muito mais rápido e fácil. Em teoria é só fazer downgrade da versão do microapp nas depedencias dentro do seu projeto "Build".

Dependências e resolução de dependências 🤝

Muitas pessoas optam por criar um pacote somente para gerenciar as versões de dependências globalmente, chamado de "shared_dependencies" na maioria das vezes. Todas as dependências comuns ficariam dentro deste pacote e seriam compartilhadas por todos os microapps.

Embora seja uma proposta interessante, na verdade é desnecessária. O próprio pub tool do Dart faz esse papel com maestria, como podemos ver em exemplos aqui e aqui.

Uma grande vantagem dessa abordagem arquitetural é que cada microapp pode ter suas próprias dependências. Por exemplo, um microapp pode usar somente o ValueNotifier/ChangeNotifier, enquanto outro pode usar MobX. No final, o pub tool resolve todas as dependências de forma eficiente e inteligente.

Como os microapps se comunicam? 📢

Aqui talvez tenha um ponto critico em sua arquitetura de microapps. Dependendo do ponto em que se quer chegar vários microapps podem ou não trocar dados, e como nós fazemos isso?

Uma das alternativas e uma das mais usadas é com Streams, talvez até usando o já conhecido EventBus, outra é usar um estado compartilhado encapsulado em um package separado, ou para ser mais simples também podemos enviar argumentos diretamente nas rotas, porém uma infinidade de alternativas podem ser desenvolvidas além destas.

Um ponto a ser destacado é que com Flutter Web dependendo da abordagem pretendida, a passagem de parâmetros via rotas(direto na URL) é muito melhor quando uma URL fica exposta ao publico ou pode ser compartilhada, com streams sua camada de apresentação e todo resto pode quebrar em algum momento.

Algumas vantagens escondidas 🛸

Embora muitos desenvolvedores tenham reclamado sobre o build_runner, eu também já tive minhas dificuldades com ele. No entanto, minha experiência com a arquitetura de microapps foi bastante positiva. É possível executá-lo isoladamente em cada microapp, que teoricamente é um pacote diferente, tornando-o muito mais rápido e eficiente.

Outra vantagem dessa arquitetura é a possibilidade de separar a lógica de negócios e os serviços da camada de apresentação. Por exemplo, podemos ter um pacote especializado para consumir uma API e conter as regras de negócio, enquanto outro microapp contém a camada de apresentação e suas reatividades.

Did you find this article valuable?

Support Lucas Náiade's blog by becoming a sponsor. Any amount is appreciated!