Engenharia iOS

[Arquitetura iOS #10] RIBs da Uber: dividindo o app pela lógica de negócio

RIBs divide um app por unidades de lógica de negócio, não por telas. Este texto explica os componentes sem tela, por que a arquitetura é usada apenas em organizações muito grandes e como ela difere de VIPER.

4 min de leitura
Imagem de capa de [Arquitetura iOS #10] RIBs da Uber: dividindo o app pela lógica de negócio

No artigo sobre VIPER (View·Interactor·Presenter·Entity·Router), mencionei rapidamente “RIBs, criado pela Uber e inspirado em VIPER”. Nesta edição, vamos tratar do assunto de verdade. No Brasil, também é conhecido como a arquitetura adotada pela Toss.

Há uma única chave para entender RIBs. Todas as arquiteturas abordadas até agora (MVC·MVVM·VIPER·ReactorKit) usavam as telas como unidade básica. RIBs abandona essa premissa e divide o app por lógica de negócio, não por telas.


A existência de componentes sem tela

RIBs é a sigla de Router·Interactor·Builder. Esses três são obrigatórios em cada componente (RIB); Presenter e View só são adicionados quando necessário.

  • Interactor: O núcleo da lógica de negócio, o cérebro do RIB.
  • Router: Gerencia a árvore fazendo attach e detach de RIBs filhos.
  • Builder: Monta um RIB e injeta suas dependências.
  • Presenter·View: Opcionais. Existem apenas em RIBs que precisam de uma tela.

O fato de “View ser opcional” é decisivo. Pense no estado “em corrida” de um app de transporte. Ele abrange o mapa, o cartão com os dados do motorista e a lógica de preparação do pagamento, mas não é uma única tela. No RIBs, ele vira um RIB sem tela, viewless, com RIBs filhos que têm telas conectados abaixo dele.

O app inteiro se torna uma árvore de RIBs. As mudanças de estado do app, como login e status da corrida, são mudanças no formato da árvore. Ao sair da conta, o RIB LoggedIn é removido por completo da árvore, junto com suas telas e lógica. Gerenciar estado é, na prática, gerenciar a árvore.

Diagrama da estrutura em árvore de RIBs e da distinção entre RIBs sem tela e RIBs com View
Estados do app, como login e corrida, definem o formato da árvore

Por que apenas organizações muito grandes usam isso?

RIBs foi projetado desde o início para “quando centenas de pessoas criam um único app”. Dezenas de equipes adicionam código simultaneamente ao app da Uber, e a separação por tela não conseguia criar limites entre equipes: a lógica de várias equipes se misturava em uma só tela.

Ao dividir por RIB, cada equipe passa a ser dona do próprio subtree de RIBs. Como o Builder força os pontos de injeção de dependência, não há como tocar no interior do RIB de outra equipe. É a “imposição de limites” da série sobre modularização realizada no nível da arquitetura.

A Toss adotou RIBs pelo mesmo motivo. Em uma superapp com dezenas de serviços financeiros, transformar cada serviço em um subtree de RIBs deixa claro quando anexá-lo e removê-lo.

Por outro lado, todas essas vantagens se tornam custos para equipes pequenas.

Primeiro, RIBs tem mais boilerplate que VIPER. Um RIB normalmente gera quatro ou cinco arquivos. Por isso, a Uber também fornece templates de geração de código.

Segundo, a curva de aprendizado é íngreme. É preciso aprender o design da árvore, os momentos de attach/detach e a injeção de dependência por escopo para toda a equipe compartilhar o mesmo modelo mental.

Terceiro, isso entra em conflito com o pensamento centrado em telas. Especificações normalmente são feitas por tela, enquanto RIBs divide por estado, então é necessário traduzir entre os dois na fase de design.

Qual é a diferença em relação ao VIPER?

Pelos nomes dos componentes, parece uma variação do VIPER, mas a diferença é fundamental.

VIPER RIBs
Unidade básica Tela Lógica de negócio
Componente sem tela Impossível viewless RIB
Navegação Router faz a transição de tela Router faz attach/detach da árvore
Objetivo Separar as responsabilidades de uma tela Separar a propriedade do código por unidade organizacional

O Router do VIPER cuida de “como ir para a próxima tela”, enquanto o Router do RIBs cuida de “quais componentes de lógica devem estar ativos no estado atual do app”. Mesmo nome, pergunta diferente.

Ilustração da propriedade do código por equipe em RIBs, dividida nos subtrees TEAM A, B e C
O verdadeiro objetivo do RIBs é cada equipe ser dona do próprio subtree

Resumo

  • RIBs é a arquitetura da Uber para dividir um app em uma árvore de unidades de lógica de negócio, não de telas.
  • RIBs sem tela são permitidos, e as mudanças de estado do app são expressas como attach/detach na árvore.
  • O objetivo é separar a propriedade do código por equipe e impor limites, por isso RIBs se destaca em organizações com centenas de pessoas. Uber e Toss são exemplos representativos.
  • Para equipes pequenas, boilerplate e curva de aprendizado superam os benefícios. Como explicado no guia de escolha da edição 8, o tamanho da equipe é o principal fator.

Com isso, completamos as partes da série de arquitetura iOS que haviam sido apenas mencionadas. De MVC a RIBs, todas as arquiteturas são respostas diferentes à mesma pergunta: “Onde a lógica deve ficar?”

Continue lendo

Série de arquitetura iOS