Engenharia iOS

[Arquitetura iOS #8] Guia para escolher uma arquitetura iOS

Se você acompanhou esta série de arquitetura iOS até aqui, todas as opções já estão na mesa: MVC, MVVM, MVP, VIPER, Clean Architecture, MV e TCA.

5 min de leitura
Imagem de capa de [Arquitetura iOS #8] Guia para escolher uma arquitetura iOS

Se você acompanhou esta série de arquitetura iOS até aqui, todas as opções já estão na mesa: MVC, MVVM, MVP, VIPER, Clean Architecture, MV e TCA.

Mas a pergunta mais difícil ainda permanece. “Então, qual devemos usar no nosso app?”

É verdade que “não existe resposta certa, apenas trade-offs”, mas isso, por si só, não permite decidir. Neste último artigo da série, vamos organizar critérios concretos para tomar essa decisão.


Critério 1: tamanho da equipe — arquitetura é um problema de pessoas

Primeiro, ajuste o peso da arquitetura ao número de pessoas, não à quantidade de código.

Para uma equipe de 1–2 pessoas, velocidade é mais importante que uniformidade estrutural. No SwiftUI, MV (Model–View) + Repository é suficiente; com UIKit, separar navegação e rede do MVC também. Nesse tamanho, adotar VIPER (View, Interactor, Presenter, Entity, Router) ou TCA (The Composable Architecture) pode fazer o tempo gasto mantendo a estrutura consumir o desenvolvimento de funcionalidades.

A partir de 3–10 pessoas, a equipe precisa concordar sobre “onde fica a lógica”. MVVM + UseCase/Repository é o padrão mais equilibrado nessa faixa. Manter a mesma estrutura em cada tela reduz o custo de code review e onboarding.

Com mais de 10 pessoas em vários squads, uniformidade e limites de módulos vêm primeiro. É aqui que entram a modularização por funcionalidade com camadas de Clean Architecture ou a escolha do TCA como padrão quando a complexidade de estado é alta. VIPER e RIBs também foram adotados por organizações desse porte.


Critério 2: vida útil do app — quanto mais longa, mais vale investir em limites

Criar camadas para um app de vida curta (protótipo, MVP (Minimum Viable Product) de validação ou app de evento) é desperdício. O objetivo é criar rápido e aprender rápido.

Para um produto que viverá por 3 anos ou mais, a história é diferente. A API do servidor será reformulada, o design será refeito e você passará por migrações de framework como UIKit→SwiftUI. O que compensa aqui não é um padrão chamativo, mas limites: um Repository que esconde as fontes de dados e um UseCase que contém as regras de negócio. Com limites, é possível substituir partes; sem eles, é preciso reescrever tudo.

Tamanho da equipe, vida útil do app e complexidade de estado: três eixos decidem
Tamanho da equipe, vida útil do app e complexidade de estado: três eixos decidem

Critério 3: complexidade de estado — o único eixo que justifica o TCA

Se o app apenas “recebe dados do servidor, exibe-os e envia as entradas de volta”, MVVM/MV é suficiente. Já quando várias telas editam o mesmo estado ao mesmo tempo, ou quando sincronização em tempo real, mesclagem offline e undo complexo se combinam, o custo do TCA para controlar à força os caminhos de mudança de estado começa a ser justificado.

Como vimos no artigo anterior, TCA não é uma escolha errada, e sim cara. Se a complexidade nesse eixo for baixa, você não recuperará esse custo.


Em uma página

Situação Recomendação
Solo · Protótipo MV (SwiftUI) ou MVC + separação mínima
Equipe pequena · App de serviço geral MVVM + Repository (UseCase se necessário)
UIKit legado · Alto custo para adotar binding MVP + Coordinator
Organização grande · Produto de longa duração Camadas de Clean Architecture + modularização por funcionalidade
Domínio com estado complexo TCA (pressupondo investimento da equipe em aprendizado)

Mais importante que a tabela é isto: você pode começar em qualquer célula e depois migrar para uma célula vizinha. Mas isso exige uma condição.


Invariantes que você deve preservar, qualquer que seja a escolha

O princípio que atravessa toda a série pode ser resumido assim:

Impeça que a View acesse diretamente a rede ou o banco de dados e mantenha as regras de negócio fora do código da tela.

Se essa invariante for preservada, migrar de MVC para MVVM e de MVVM para TCA se reduz a um problema de “substituição da camada de tela”. Se ela ruir, adotar qualquer arquitetura da moda resulta em uma reescrita completa. O nome da arquitetura fica no currículo, mas são os limites que mantêm o produto vivo.

Por fim, a migração de arquitetura deve ser incremental: comece pelas telas novas, em vez de fazer uma mudança de uma vez. Reescrever telas existentes que funcionam apenas por causa de uma moda geralmente termina em arrependimento.

Arquitetura é uma ferramenta, não um destino
Arquitetura é uma ferramenta, não um destino

Encerrando a série

Estas são as oito partes resumidas em uma frase cada.

  • MVC: entender a concentração de responsabilidades no UIViewController é o ponto de partida
  • MVVM: extraia o estado da tela e sincronize-o com binding; sem binding, fica pela metade
  • MVP vs MVVM: a diferença é saber se o objeto intermediário conhece a View
  • VIPER: separação levada ao extremo; seu legado sobrevive no Coordinator e no UseCase
  • Clean Architecture: dependências apontam apenas para dentro; comece pelo Repository
  • TCA: controle os caminhos de mudança de estado quando a complexidade justificar o custo
  • O debate sobre MV: o essencial é onde a lógica fica e a direção das dependências, não o nome
  • Guia de escolha: escolha pelo tamanho da equipe, vida útil do app e complexidade de estado; preserve as invariantes e migre gradualmente

Arquitetura é uma ferramenta, não um destino. Invista em limites para poder mudar conforme a equipe e o app crescem.

Continue lendo