Aplicação de arquitetura BLoC com SwiftUI

À medida que os frameworks de desenvolvimento se modernizam, é necessário que os padrões arquiteturais se atualizem para manter a facilidade de manutenção, alta legibilidade, performance e outros aspectos dos produtos. Quando falamos de frameworks para desenvolvimento mobile, um grande marco é a migração dos frameworks de um padrão imperativo, no qual tínhamos o UIKit para iOS e o Android Views para Android, para o SwiftUI e o Jetpack Compose, em iOS e Android, respectivamente. Além dos nativos, surgiram outros frameworks híbridos e declarativos, como o Flutter baseado em Dart. 

Quando falamos no Flutter, a sua estruturação baseada em árvore de widgets gera um acoplamento entre as views e a parte de negócio, devido ao fato de o State Provider ser uma propriedade dos widgets. Para tentar criar um código mais clean, surge então o Business Logic Component (BLoC). Um padrão arquitetural que separa melhor as responsabilidades dos estados e realiza esse desacoplamento. O objetivo deste artigo é demonstrar a viabilidade de se aplicar o BLoC em apps nativos com SwiftUI. 

 

Falando um pouco mais sobre o BLoC 

A palavra BLoC foi inventada pela Google para simbolizar “Business Logic Components”. A ideia é centralizar o máximo possível da lógica de negócios em Dart puro para que possa ser reutilizada em várias plataformas. Como consequência, o BLoC promove um design mais modular e de fácil manutenção.  

Originalmente popularizado no desenvolvimento com Flutter, ele se baseia em uma arquitetura de gerenciamento de estados reativos, no qual as mudanças no estado da aplicação são propagadas por meio de fluxos de dados assíncronos. 

 

Princípios do BLoC 

  • Separação de preocupações: o BLoC promove uma clara distinção entre a lógica de negócio e a interface do usuário. Com isso, cada camada do aplicativo tem responsabilidades bem definidas, facilitando a manutenção e a escalabilidade do código. 
  • Gerenciamento de estado: no padrão BLoC, o estado da aplicação é gerenciado de forma centralizada. Cada mudança no estado é emitida como um evento, que é processado pelo BLoC, resultando em um novo estado. 
  • Reatividade: o BLoC utiliza streams (fluxos de dados) para comunicar mudanças de estado entre a lógica de negócio e a interface do usuário. Isso permite uma atualização eficiente e reativa da UI, refletindo imediatamente qualquer alteração no estado. 
  • Testabilidade: separar a lógica de negócio em componentes distintos facilita a criação de testes unitários. Como o BLoC não depende diretamente da interface do usuário, é possível testar a lógica de forma isolada, garantindo maior confiabilidade do código. 

 

Principais componentes do BLoC 

  • Events (Eventos): representam ações que devem ser tratadas pelo BLoC. Por exemplo, um evento pode ser acionado quando o usuário clica em um botão ou quando um dado é carregado de uma API. 
  • States (Estados): representam o estado atual da aplicação. Cada vez que um evento é processado pelo BLoC, ele emite um novo estado. 
  • BLoC: é o componente central que recebe eventos, processa a lógica de negócio associada e emite novos estados. Ele atua como um intermediário entre a interface do usuário e a lógica de negócio. 

 

Aplicação do BLoC em SwiftUI 

A ideia de implementar o BLoC em SwiftUI envolve adaptar os conceitos e princípios dele para o ecossistema Swift. Isso significa criar uma estrutura onde a lógica de negócio e o gerenciamento de estados são claramente separados da interface declarativa do SwiftUI.  

Existem algumas vantagens em se aplicar o BLoC no SwiftUI. Podemos citar que está cada vez mais comum projetos que misturam features em Flutter e features em Swift, e com essa implementação, os desenvolvedores podem manter o padrão arquitetural para as duas linguagens ao invés de usar MVVM ou VIPER em Swift e o Bloc em Flutter, por exemplo. Essa uniformização mantém a unidade da arquitetura do projeto. 

 

Benefícios do BLoC em SwiftUI 

  • Manutenção facilitada: com a lógica de negócio desacoplada da interface, a manutenção e atualização do código se tornam mais simples. 
  • Reutilização de código: componentes de lógica de negócio podem ser reutilizados em diferentes partes da aplicação ou até mesmo em diferentes projetos. 
  • Testes mais simples: testar a lógica de negócio de forma isolada torna a aplicação mais robusta e confiável. 
  • Consistência na interface: a interface do usuário reage de forma consistente às mudanças de estado, resultando em uma experiência de usuário mais suave e previsível. 

Implementar o BLoC em um ambiente SwiftUI pode trazer uma nova camada de organização e eficiência ao desenvolvimento de aplicativos iOS, mantendo-se alinhado com as melhores práticas de desenvolvimento reativo e modular. 

 

O uso do Combine em SwiftUI 

Já existem frameworks como o Combine no SwiftUI, que funciona como um streamer e atualiza a view conforme a existência de eventos. No entanto, para um maior controle da solução e reduzir acoplamento, decidimos não utilizar o Combine e criar o próprio fluxo de eventos e estados. Isso também respeita uma das premissas do BLoC, que é manter a lógica de negócios agnóstica em relação a frameworks. 

 

Comparação com The Composable Architecture (TCA) 

O conceito do BLoC é um forte concorrente ao The Composable Architecture (TCA), que tem ganhado espaço dentro da comunidade Swift. Existem semelhanças e diferenças entre eles que cabem aos desenvolvedores adotar a abordagem que melhor se encaixa às necessidades do projeto. 

O TCA é uma biblioteca que tem o mesmo princípio do BLoC, porém dá um passo a mais ao ligar os estados diretamente com o SwiftUI. No entanto, o lado negativo disso é que os desenvolvedores perdem muito o controle do que está implementado e das regras de negócio adotadas no projeto. Em casos específicos, fica impossível desacoplar as views do TCA para utilizar outro tipo de abordagem. Inclusive, esse é um ponto que aumenta muito a curva de aprendizado dessa biblioteca. 

Já o BLoC contém um limite evidente que separa a View das regras de negócio. Tudo fica dentro dele e não há por que os desenvolvedores unificarem as coisas. Talvez isso aconteça porque o Flutter está há mais tempo no mercado que o SwiftUI, e os desenvolvedores já discutiram muitos pontos que ainda estão amadurecendo dentro do SwiftUI. Trazer a solução do BLoC para dentro do SwiftUI talvez seja unificar o melhor dos dois mundos, ganhando os benefícios do TCA e unificando-os com os benefícios do BLoC. 

Essa desconexão do BLoC com a View permite aos desenvolvedores total flexibilidade em implementar as telas conforme achar necessário. Tanto o controle de fluxo quanto a arquitetura de cada jornada pode ser lapidada para cada problema que aparecer durante o desenvolvimento. Vale ressaltar que, em um projeto, buscamos padronizar a implementação e adotar um estilo único de desenvolvimento. Porém, existem problemas e cenários que exigem uma flexibilidade maior da arquitetura ou do padrão de projeto adotado. O TCA, no quesito flexibilidade, é extremamente limitado. 

 

Swift Bloc 

Para concluir, gostaria de compartilhar o desenvolvimento de uma biblioteca que está sendo desenvolvida por mim e pelo Brenno Giovanini com o objetivo de trazer o BLoC para o Swift/SwiftUI. Essa solução tem como inspiração tanto os trabalhos feitos pelo time do TCA para o SwiftUI como também pelo próprio padrão BLoC utilizado no Flutter. Ambas as tecnologias são muito boas de trabalhar e o BLoC no SwiftUI busca unir os conceitos para que os desenvolvedores tenham maior liberdade de desenvolvimento nos projetos Swift: https://github.com/swift-bloc/bloc 

 

*As opiniões aqui colocadas refletem a minha opinião pessoal e não necessariamente a opinião da Compass UOL. 

Gostou da solução? Nós podemos ajudar!

Conheça nossos conteúdos gratuitos, direcionados aos assuntos de sua preferência!

Enviar

Receba nosso conteúdo

Gostaria de receber de forma gratuita mais conteúdos sobre este ou outros assuntos? Preencha o formulário abaixo e receba nosso conteúdo gratuito!

Parabéns!

Você receberá nosso conteúdo em breve!

Atenção

Tivemos um problema com seu formulário, tente novamente.