No PET-Redação dessa semana, vamos tentar entender a arquitetura Flux, comparando-a com o famigerado MVC. Então pega o teu café e nos acompanha nessa redação descontraída.
Flux é a arquitetura que o Facebook criou para melhorar o desenvolvimento de aplicações web nos tempos modernos. Mas antes de entrarmos no assunto, temos que entender o porquê da existência dessa arquitetura e como ela facilita o desenvolvimento de aplicações.
Antes de utilizar o Flux, o Facebook utilizava o MVC, a arquitetura mais famosa e conceituada quando o assunto é desenvolvimento de aplicações. Essa fama vem da separação de interesses que essa arquitetura oferece de forma a otimizar a compreensão e escrita de código. Só que, como tudo na vida, o MVC não é só flores, e um dos aspectos negativos é a complexidade que a aplicação toma quando pensamos em escalabilidade. Ou seja, para aplicações menores, com meia dúzia de funcionalidades, o MVC serve muito bem. Mas para pra pensar, quantas funcionalidades tem o Facebook? Tem o sistema de chat (Messenger), posts, grupos, galeria de fotos e vídeos, stories, eventos, serviços de streaming, etc. Agora vamos tentar imaginar um cenário em que isso está modelado em cima do MVC.
É praticamente impossível identificar alguma anomalia em um diagrama nesse estado. E se existe um loop infinito nessas comunicações, como vamos saber a partir desse diagrama? Foi por conta disso que o Facebook criou o Flux para tentar resolver esses tipos de problemas.
Como eu falei anteriormente, o Flux é uma arquitetura para o desenvolvimento de aplicações web com o propósito de evitar a comunicação ambígua que existe entre as views e os models, ou seja, criar um fluxo de dados unidirecional.
A arquitetura é dividida nas seguintes camadas:
-
Actions: são objetos contendo o identificador do elemento que queremos mudar e a informação que será atualizada no store;
-
Dispatcher: funciona como o controlador do tráfego que entra na aplicação, gerenciando as actions que entram no sistema;
-
Store: serve como a camada de dados que atualiza cada vez que uma ação é realizada;
-
Views: que é a camada de visualização e realiza a re-renderização cada vez que o store muda de estado.
Com o diagrama fica mais fácil de ver o fluxo de dados. Ainda, é possível enviar uma action a partir da view, acionando o dispatcher para receber essa ação.
Deu pra perceber que o Dispatcher é o coração dessa arquitetura, né? Ele acaba sendo a parte mais importante da arquitetura na medida em que a aplicação cresce, pois é responsável por todo o gerenciamento das ações e das dependências que essas geram na camada de dados.
Implementando essa arquitetura, eu consigo lembrar de dois exemplos que estão sendo bastante visados no mercado de trabalho, o React, framework de código aberto que hoje é mantido pelo Facebook, e o Vue, outro framework de código aberto que é mantido pela comunidade. Essas ferramentas têm um sistema de “gerenciamento de estados” que utiliza a arquitetura Flux. Para o React, esse sistema se chama Redux, e no Vue, ele é chamado de Vuex.
Essas duas bibliotecas implementam o Flux de forma a otimizar o fluxo de dados, diminuindo a troca de mensagens entre o cliente e o servidor, e a escrita de código, criando uma camada exclusiva para os dados precisam ser persistidos em várias camadas do sistema.
No Redux, não temos a camada do Dispatcher, pois a biblioteca depende de funções puras ao invés de emissores de evento, eliminando essa camada de gerenciamento das ações. Outra diferença do Redux para o Flux, é que não existe “mudança” nos dados. O que realmente acontece é uma nova instância daquele dado com outro valor, pois a ferramenta funciona com uma política de objetos imutáveis para garantir a consistência dos dados.
O funcionamento da ferramenta tem o diagrama mais ou menos como na imagem abaixo:
Podemos tentar entender com o template exemplo quando criamos um react-app com a flag –template redux:
npx create-react-app my-app --template redux
Acessando o projeto após a sua criação, podemos ver a base de um aplicativo em React com o Redux embutido. O exemplo é bem simples, um acumulador de clicks, mas dá pra ver e entender todo o fluxo do Redux.
A página Main.js tem o seguinte template:
Para os botões de somar (+), diminuir (-) e adicionar uma quantia (Add Amount), existe um evento onclick sendo emitido, dessa forma:
Batendo o olho, vemos a palavra-chave dispatch sendo chamada como uma função, e passando como parâmetro uma outra função, seja ela a increment() ou decrement(). A aplicação está acessando o store com a chamada do dispatch, e passando como parâmetro, a ação que ela quer realizar.
Mas onde estão esses métodos increment() e decrement()?
Eles estão lá no arquivo counterSlice.js, onde são definidos os reducers, ou ações. Essas ações que fazem atualização nos estados da aplicação. Nesse exemplo simples, o único estado que está mudando é o valor do acumulador na tela. Cada vez que clicamos para somar ou subtrair desse acumulador, é realizada uma ação no sistema para ajustar esse estado.
Os reducers sempre recebem dois parâmetros, o state, que se refere ao estado atual, e um segundo parâmetro, o action, que pode ser uma quantia a ser incrementada, como está sendo realizado no incrementByAmount.
Por outro lado, o Vuex é implementado bem na proposta do Flux, contendo essas camadas bem definidas, como dá pra ver no diagrama abaixo:
Na tela de Login dessa aplicação, temos os métodos para realizar o login do usuário:
Conseguimos ver que o método está chamando this.$store.dispatch(), a mesma palavra-chave utilizada no Redux, porque o que está acontecendo é exatamente a mesma coisa. A aplicação está realizando uma ação no store. No lado do store da aplicação, a action login será executada.
Essa action recebe dois parâmetros, também. O primeiro é o context, contexto atual da aplicação, ou seja, os valores atuais do sistema. Esse objeto está sendo desestruturado para pegar apenas o método commit do store, que serve para uma ação realizar uma mutation no store, o que, de fato, irá mudar o valor do estado.
Nesse caso, acontece um commit de ‘auth_success’ ou ‘auth_error’ dependendo da resposta da API. Caso o login for realizado, a mutação de sucesso será realizada, caso contrário, será realizada a mutação de erro.
As mutações trocam o valor do estado, literalmente. Recebem os valores vindos das ações e sobrescrevem aquele valor atual com esse valor recebido.
Para acessar esse projeto inteiro, vou deixar aqui o link para o repositório do código dessa aplicação. Nos commits, eu tentei deixar organizado e em ordem, como se fosse um tutorial passo-a-passo. Seguindo os commits, será possível implementar essa aplicação e ver ela funcionando.
Os dois frameworks têm as suas particularidades, mas o conceito é o mesmo, pois os dois são baseados na mesma arquitetura.
Para ver e entender melhor, tanto Vuex, quanto Redux, eu recomendo este artigo. O Sunil Sandhu implementa a mesma aplicação em React e em Vue, utilizando Redux e Vuex, mostrando o passo-a-passo e as diferenças de cada um.
Referências: