Este é o primeiro post de uma série de publicações explicando minha compreensão da arquitetura de aplicativos de Flutter. Eu te aviso - será muito autoconfiante .
Até agora planejado:
Prefácio
Trabalho com programação há cerca de 20 anos. Comecei o desenvolvimento móvel há 4 anos com o Xamarin.Forms, porque a plataforma cruzada era a única motivação para mim como desenvolvedor independente. O Xamarin.Forms está literalmente pressionando você a usar o padrão MVVM, já que a UI é definida em XAML, e você precisa de algum tipo de camada para colar a UI com o Model. No processo de trabalho com o Xamarin, conheci o ReactiveUI e fiquei literalmente cativado pelos fluxos e extensões reativas ( Rx ) que tornaram meus aplicativos mais confiáveis.
Enquanto as MVVMs do Xamarin.Forms estavam prontas para uso, quando mudei para o Flutter, fiquei surpreso por não haver padrões de design semelhantes. Comecei a pesquisar as várias abordagens propostas, mas nenhuma das disponíveis me satisfazia completamente:
- InheritedWidget : como não consegui atualizar apenas a parte alterada da árvore de widgets, usei-a apenas para acessar as classes de modelo que publicam fluxos de dardo (Dart Streams), mas logo abandonei essa ideia em favor do modelo Service Locator
- O modelo com escopo é mais interessante que o
InheritedWidget
, mas não me deu tanta flexibilidade quanto eu estava acostumado com o ReactiveUI - Redux foi o modelo recomendado por muitos desenvolvedores familiarizados com o React Native. Eu tenho um post inteiro sobre por que eu não gosto.
- BLoC : se eu ainda não tivesse começado a desenvolver meu próprio padrão no momento em que o BLoC começou a avançar, provavelmente eu o teria adotado, pois é realmente flexível e reativo. O que eu não gosto é que ele publica Stream Sinks e não posso simplesmente pegar e passar funções ou comandos para o manipulador de eventos do widget. Além disso, o BLoC não informa como estruturar seu aplicativo como um todo, nem existe uma definição clara de quão grande deve ser um determinado BLoC ou qual é seu escopo.
- MVVM : desde que eu trabalhei com ele, esta é a primeira coisa que eu esperava implementar no Flutter. Mas não! O objetivo do ViewModel é fornecer normalmente a representação do seu modelo no View por meio de ligações. Mas o Flutter não atualiza seus modelos com novos dados, sempre os reconstrói, como eu já descrevi . Além disso, o ViewModels deve sempre ser sincronizado com o modelo base, o que leva a erros desagradáveis, e a realidade mostra que a vantagem prometida de reutilizar o ViewModels em aplicativos quase nunca é alcançada. Adam Pedley tem um ótimo post sobre essas falhas
A dura verdade sobre redundância de camada
É quase um dogma a idéia de que, no desenvolvimento, você sempre deve criar seu aplicativo em várias camadas, cada uma das quais tem acesso apenas ao subjacente, pois isso permitirá:
- reutilizar camadas em outros projetos
- substitua transparentemente uma camada por outra
- simplificar o teste
No entanto:
- na minha prática, não houve nenhum caso em que observei uma reutilização completa de camadas. Se você tem um código universal que pode ser reutilizado, faz mais sentido colocá-lo em algum tipo de biblioteca universal;
- substituir camadas inteiras também não é uma prática comum. É improvável que a maioria das pessoas substitua o banco de dados após o aplicativo atingir um certo estágio de desenvolvimento, então, por que adicionar uma camada de abstração para ele? Bem, se algumas de nossas ferramentas de desenvolvimento atuais forem necessárias, a refatoração é bastante fácil;
- o que realmente funciona é a simplificação dos testes
Não sou contra o uso de camadas, no entanto, devemos seguir essa regra de forma tão imprudente quanto antes. O uso excessivo deles leva a um aumento no código e pode potencialmente criar problemas, mantendo uma única fonte de estado do aplicativo. Portanto, aplique camadas quando for realmente necessário e não com base nas "melhores práticas".
Arquitetura ideal para Flutter
Então, o que espero de uma arquitetura perfeita?
- Facilidade de entender o aplicativo. Para mim, esse é o objetivo mais importante. Novos desenvolvedores envolvidos no trabalho com código existente devem entender facilmente a estrutura de desenvolvimento
- Facilidade no desenvolvimento da equipe
- A arquitetura em si deve ser fácil de entender e manter.
- Nenhum código de modelo para muletas em desenvolvimento
- Suporte ao estilo reativo a vibrações
- Depuração fácil
- O desempenho não deve sofrer
- Facilidade de expansão
- Facilidade de teste
- Oportunidades para focar no aplicativo em vez de vagar na fonte
Independência de widget
Com base na natureza dos elementos da interface sem estado, nenhuma página / widget no Flutter deve depender ou influenciar outros. Isso leva à ideia de que cada página / widget deve ser responsável por se exibir e todas as suas interações com o usuário.
Rxvms
RxVMS é uma evolução do padrão RxVAMS descrito em um post anterior , durante a aplicação prática da qual alguns problemas foram identificados e corrigidos.
O resultado atual de todos esses pensamentos é o padrão RxVMS, ou Rx-View-Managers-Services. Ele executa todas as tarefas acima com o único requisito de que você deve entender os segmentos e elementos Rx. Para ajudá-lo, dedico o seguinte post.
Aqui está um breve resumo da minha inscrição

Serviços
Essas são abstrações de interfaces para o mundo externo, que podem servir como bancos de dados, APIs REST, etc. Eles não afetam o estado do aplicativo.
Gerentes
Os gerentes agrupam funcionalidades semanticamente semelhantes, como autenticação, procedimentos de pedidos e similares. Os gerentes manipulam o estado de um objeto.
Qualquer alteração no estado (alterações nos dados do aplicativo) deve ser feita apenas pelos gerentes. Como regra, os próprios gerentes não armazenam dados, exceto em casos críticos para constantes de desempenho ou tempo de execução.
Os gerentes podem servir como fontes de dados proxy, caso seja necessária uma certa transformação após uma solicitação dos serviços. Um exemplo é a combinação de dados de duas ou mais fontes para exibição em uma Visualização.
Os gerentes podem interagir entre si.
Visualizações
Normalmente, é StatefullWidget ou StreamBuilder, capaz de usar dados de gerentes e serviços. Pode ser uma página inteira ou um widget. As visualizações não armazenam nenhum estado e podem entrar em contato diretamente com os serviços enquanto essa regra for respeitada.
Objetos de domínio
Embora não incluídas no diagrama, são entidades importantes que representam o modelo de negócios. Em outros padrões, eles podem pertencer a uma camada separada ( modelo de negócios ) em conjunto com a lógica de negócios. Aqui, no RxVMS, eles não contêm nenhuma lógica que altera o estado do aplicativo. Quase sempre, esses são tipos de dados simples - objetos de dados simples (se eu os incluísse no padrão, pareceria o RxVMMS, que é um pouco longo e causa confusão - a VM pode ser confundida com um ViewModel). Logicamente, os objetos de domínio estão localizados na camada de gerenciadores.
As postagens a seguir revelarão a essência e a interação desses elementos.