Introdução ao padrão BLoC

Tempo de leitura: 6 minutes

Introdução ao padrão BLoC

Também introduzimos uma primeira estratégia simples de gerenciamento de estado compartilhado entre componentes, que consistia em elevar o estado para o componente superior e fazer uso de perfuração de propriedade.

 

Apresentação do padrão BLoC

O padrão BLoC foi projetado por Paolo Soares e Cong Hu, do Google, e foi apresentado na Dart Conference 2018.

BLoC significa Business Logic Component.

O objetivo com a equipe do Google projetada neste padrão era a reutilização de código entre seus aplicativos móveis, usando Flutter com Dart, e web, usando Angular Dart.

Nesta apresentação da Dart Conference 2018, Paolo Soares apresentou o padrão, mas é uma implementação concreta para o Dart que eles aplicaram em Flutter e Angular Dart.

No entanto, o conceito de padrão pode ser mais abstrato e amplo. Portanto, é agnóstico e pode ser usado em qualquer tecnologia como por exemplo com Redux, que é uma implementação do Flux e existem muitas bibliotecas em diferentes tecnologias.

Minha intenção neste artigo é apresentar os conceitos de um ponto de vista mais abstrato válido para qualquer tecnologia.

Apresentando o padrão BLoC

Um BloC é um componente intermediário entre as visualizações e nosso modelo, como o apresentador quando usamos MVP ou o modelo de visualização quando usamos MVVM.

O modelo é um conceito bastante amplo, dependendo do tamanho e da arquitetura de seu aplicativo. Pode ser de nossa camada de dados em uma arquitetura simplificada para nosso domínio ou hexágono se usarmos Arquitetura de Clã ou Arquitetura Hexagonal.

Como o Redux, o BloC é baseado em conceitos de programação reativa usando o padrão observador, mas é muito mais simples e, portanto, mais versátil.

O padrão BLoC inicialmente, conforme apresentado pelo Google, tem vários objetivos:

  • Centralize a lógica de negócios
  • Centralize as mudanças de estado
  • Mapeie para o formato que a visualização precisa

Para cada visão (componente ou widget) ou conceito importante o suficiente, teremos seu BloC correspondente.

Por exemplo, a visualização (componente ou widget) que representa uma página ou que representa um estado compartilhado por mais de uma visualização, seriam exemplos em que faria sentido criar um BLoC.

 

Centralizar la lógica de negocio

O Google apresentou esse padrão no contexto de ter aplicativos sem uma arquitetura definida, com componentes muito grandes, com lógica de negócios e onde também são feitas chamadas para uma API dentro dos componentes.

A ideia é extrair tudo o que não seja visualização, como a lógica de negócios dos componentes do framework de UI em classes chamadas BLoC, não relacionadas a qualquer tecnologia ou biblioteca.

Essas classes não podem ter nenhuma dependência de uma biblioteca específica, dependem de abstrações e estas devem ser injetadas.

Dessa forma, usando o princípio de inversão de dependência, uma classe BLoC deve conter apenas lógica e pode ser melhor escalada para mudanças futuras ou para ser usada em diferentes tecnologias.

Centralize as mudanças de estado

Essas classes BloC irão centralizar as mudanças de estado que ocorrem no aplicativo.

Dessa forma, essas classes BLoC se encarregariam de receber as ações ou eventos que ocorrem na aplicação, e que modificam o estado.

Eles mantêm o estado em cache na memória e também são responsáveis ​​por comunicar as mudanças de estado a todas as partes envolvidas (componentes ou widgets), uma vez que deve ser observável.

Se você se lembra do que vimos em artigos anteriores sobre gerenciamento de estado simples, onde o objetivo de elevar o estado ao componente superior e usar o detalhamento de propriedade era ser capaz de comunicar mudanças de estado compartilhadas para vários componentes ou widgets.

Uma das limitações dessa estratégia era que, quando o estado do componente pai mudasse, todos os filhos descendentes seriam renderizados, embora não usem o status do componente pai para renderizar.

Com o padrão BLoC, esse problema é resolvido, porque apenas os componentes ou widgets inscritos nas mudanças de estado do BLoC são renderizados.

 

Mapeie para o formato que a visualização precisa

Os BLoCs também ficarão encarregados de formatar os dados conforme exigido pelas visualizações, dessa forma essa lógica de apresentação da formatação também será reutilizável.

Fluxo de dados unilateral

Em padrões como MVVM, a comunicação entre a visualização e o modelo de visualização tanto para representar o estado quanto para alterá-lo ocorre por meio de vinculação de dados bidirecional.

O problema com essa abordagem é que é muito difícil depurar e manter aplicativos complexos porque há saltos encadeados entre diferentes visualizações e modelos de visualização.

Assim como o Redux, o BloC é baseado em um fluxo de dados unilateral.

A ligação entre a visualização e o estado é apenas em uma direção, lendo o estado da visualização para renderizar.

Para modificar o estado, isso é feito explicitamente, primeiro tratando os eventos no componente ou widget e, em seguida, invocando ações ou eventos no bloco que modificam o estado no BLoc.

Se você olhar o diagrama, o padrão BloC não entra em detalhes sobre o que acontece dentro do BloC, que é visto como uma caixa preta.

BLoC como uma caixa preta

Um BLoC visto como uma caixa preta é um componente que recebe eventos ou ações como entradas e tem um ou mais estados observáveis ​​como saída.

Possíveis implementações

Vimos a ideia mais abstrata do padrão e, a partir daqui, uma variedade de implementações possíveis se abre.

É importante diferenciar o padrão de suas implementações específicas, para posteriormente podermos adotar aquele que mais nos convém para o nosso projeto.

Várias entradas e várias saídas

Na apresentação de Paolo Soares, a implementação que ele usou tinha várias entradas e várias saídas.

Teríamos assim um método para cada ação possível a ser realizada ou se quisermos torná-la toda reativa podemos ter um observador para cada entrada, isso é secundário.

Tanto as entradas quanto as saídas reativas são a implementação que o Paolo Soares apresentou e vocês podem ver no vídeo.

Neste cenário, o tipo de saída está aberto às suas necessidades, várias classes de estado que encapsulam modelos de apresentação, valores primitivos, etc.

Uma entrada e uma saída

Existe a possibilidade de reduzir as entradas e saídas do BLoC para um.

Dessa forma, precisaríamos de uma hierarquia de eventos ou ações que relaciona as possíveis ações que existem para uma visão.

Teríamos um método por exemplo dispatch no BloC e que receba o evento ou ação a ser realizada por parâmetro e neste ou em outro método devemos ter um switch que decide o que fazer com base no argumento.

Teríamos também uma única saída, tendo assim uma classe de estado que representa todo o estado da visualização (dados, barra de progresso visível ou não, mensagens de erro etc …) e um mapeamento é necessário.

Estado imutável

Os frameworks declarativos são baseados na imutabilidade, os componentes quando o estado muda são totalmente reconstruídos e se usarmos o estado imutável, um melhor desempenho é obtido.

Isso porque é mais rápido saber se dois objetos que representam o estado são diferentes se forem uma instância diferente do que comparar todas as suas propriedades, filhos, etc …

Portanto, o padrão BLoC é recomendado para usá-lo também com um estado imutável, pois desta forma favorecemos o desempenho e eliminamos a complexidade na comparação de estados

Concepto versátil

O que eu gosto no padrão BLoC é que é uma ideia bastante simples com um alcance curto e, portanto, versátil, de modo que é perfeitamente válido em aplicações simples e compatível com Arquitetura Limpa ou Arquitetura Hexagonal para aplicações mais complexas.

No Redux, ao contrário, tem um escopo mais amplo e é pensado para ser a arquitetura completa de sua aplicação e é pior para Arquitetura Limpa ou Arquitetura Hexagonal porque elas se sobrepõem muito em termos de responsabilidades. E para aplicações simples, pode ser excessivo.

Em aplicativos simples, onde não há muita lógica de negócios, pode ser bom ter os BloCs com as responsabilidades que vimos.

Porém, em aplicações mais complexas, pode haver muitas responsabilidades para essas classes, tornando-as grandes, dificultando sua manutenção.

Nesses casos, complementar o padrão BLoC com Arquitetura Limpa ou Arquitetura Hexagonal é uma boa opção.

Ao complementar o padrão BLoc com uma das arquiteturas mencionadas anteriormente, algumas das responsabilidades do BLoC seriam assumidas por outros componentes, como casos de uso ou interceptores de aplicativos ou serviços.

Neste cenário, o padrão BLoC permanece como um padrão de apresentação onde sua principal responsabilidade é a lógica de apresentação como acontece com MVC, MVVM ou MVP quando são usados ​​com Clean Architecture.

Quando usar o padrão BLoC

É um padrão que possui conceitos em comum com outros padrões, como MVP ou MVVM.

Não há restrição nas estruturas de IU.

Ele pode ser usado em estruturas imperativas e declarativas, mas devido à sua capacidade reativa, ele se ajusta muito melhor em ambientes declarativos onde também há a necessidade de compartilhar o estado entre diferentes visualizações.

Algumas estruturas ou bibliotecas onde o padrão BLoc se encaixa bem são:
ReactJS, Angular, Flutter, VueJS, Android Jetpack Compose ou SwiftUI.

 

Conclusões

Neste artigo, vimos uma introdução ao padrão BLoC.

Eu pessoalmente me sinto mais confortável usando o padrão BLoC do que Redux porque ele se encaixa muito melhor com a Arquitetura Limpa, que é a arquitetura que eu geralmente uso.

Em artigos futuros, veremos como esse padrão pode ser complementado com Arquitetura Limpa, exemplos aplicados a Flutter e ReactJS.