Em reuniões de equipe e em vagas de emprego, é comum ouvir frases como *"nosso app usa arquitetura MVVM"* ou *"migramos para arquitetura VIPER"*. A intenção é boa: comunicar como o código está organizado. O problema é que esse vocabulário mistura dois níveis de abstração que a literatura de engenharia de software mantém separados há décadas: patterns (soluções localizadas a problemas recorrentes) e arquitetura (estrutura global do sistema, suas fronteiras e trade-offs).

Esse artigo nasce do swift-patterns-studies, um projeto Swift (base local: EstudoPatterns) em que a mesma jornada de autenticação (login e cadastro) é implementada quatro vezes, com MVVM, MVVM-C, VIP e TCA, compartilhando domínio, rede e componentes visuais. Se fossem "quatro arquiteturas" incompatíveis, cada uma exigiria reescrever metade do app. Não é o que acontece: só a camada de apresentação muda. Isso não é detalhe técnico; é a pista central para entender por que devemos chamar esses nomes de patterns, não de arquitetura.

Ao final, como costumo fazer em meus posts, você terá critérios práticos para classificar decisões no seu próximo projeto iOS e referências bibliográficas para aprofundar o tema.

Este post também foi escrito em inglês, clique aqui para acessar a versão em inglês.

O que é um pattern?

A definição mais citada vem do *Gang of Four* (Gamma, Helm, Johnson e Vlissides, 1994): um pattern descreve uma solução reutilizável a um problema que ocorre repetidamente em um contexto determinado. Não é um trecho de código para copiar e colar, nem um framework completo. É um vocabulário compartilhado: nomes, responsabilidades e consequências.

Buschmann e colaboradores (1996), no primeiro volume de *Pattern-Oriented Software Architecture* (POSA), refinam essa ideia em escalas diferentes:

  • Design patterns: organizam classes e objetos dentro de um subsistema (escala pequena).
  • Architectural patterns: descrevem a estrutura de alto nível de um sistema inteiro (por exemplo, camadas, microkernels, pipes-and-filters).

MVVM costuma aparecer na conversa como "architectural pattern" em alguns materiais. Na prática do desenvolvimento iOS, porém, ele atua quase sempre na camada de interface: como a tela guarda estado, reage a toques e conversa com serviços. Não define onde vivem repositórios, como módulos se importam ou como o app é implantado.

Martin Fowler (2002), em *Patterns of Enterprise Application Architecture*, documenta o Presentation Model, antecessor conceitual direto do MVVM: um objeto que segura o estado necessário para renderizar a view, de forma que a view permaneça o mais "burra" possível. Fowler deixa explícito que o escopo é a apresentação, não o sistema como um todo.

Características que ajudam a reconhecer um pattern

  1. Escopo limitado: responde a uma pergunta local: "Como organizo estado e eventos desta tela ou deste fluxo?"
  2. Substituibilidade: pode ser trocado sem derrubar o restante do sistema, desde que as fronteiras externas sejam respeitadas.
  3. Composição: vários patterns coexistem (MVVM + Coordinator é o exemplo clássico).
  4. Independência de infraestrutura: em teoria, o mesmo pattern de apresentação funciona com REST, GraphQL ou dados mockados, desde que a arquitetura de dados esteja bem definida em outro lugar.

Um pattern orienta; não governa o app inteiro.

Um exemplo rápido fora do iOS

Pense no pattern Strategy: você encapsula algoritmos intercambiáveis (por exemplo, diferentes políticas de desconto) atrás de uma mesma interface. Trocar a estratégia não redefine a arquitetura da loja virtual; redefine um ponto de variação. O mesmo raciocínio vale para MVVM: trocar a forma como a tela expõe estado não redefine onde as regras de negócio vivem, a menos que você tenha colocado regra de negócio dentro do ViewModel (o que seria um sintoma de fronteira mal desenhada, não um elogio ao pattern).

O que é arquitetura de software?

Se pattern é local, arquitetura é global. Bass, Clements e Kazman (2012), em *Software Architecture in Practice*, definem arquitetura como o conjunto de estruturas do sistema (elementos computacionais, relações entre eles e propriedades de ambos), escolhidas para satisfazer requisitos funcionais e, sobretudo, requisitos de qualidade (manutenibilidade, testabilidade, escalabilidade, segurança, evolução por equipes).

Robert C. Martin (2017), em *Clean Architecture*, sintetiza uma regra que virou referência na indústria: dependências apontam para dentro. O domínio (regras de negócio) não conhece UI, banco de dados nem frameworks. A apresentação e a infraestrutura são detalhes substituíveis plugados em portas estáveis (interfaces).

Philippe Kruchten (1995), com o modelo 4+1, lembra que "arquitetura" não é um único diagrama: há vistas lógica, de processos, de desenvolvimento, física e de cenários. Um pattern de UI é, no máximo, um recorte da vista lógica, nunca o mapa completo.

Checklist prático para o desenvolvedor iOS

Antes de chamar algo de "arquitetura do app", pergunte:

  1. Define fronteiras entre módulos e a direção das dependências em todo o projeto? Se não, provavelmente é pattern ou convenção de pasta.
  2. Abrange domínio, dados, infraestrutura e apresentação de forma explícita? Se não, é decisão de camada única.
  3. Permanece válida se trocar SwiftUI por UIKit, ou REST por outro transporte? Se não, é acoplado à tecnologia de UI ou de rede.
  4. Fundamenta trade-offs de equipe, deploy, testes de integração e evolução? Se não, é organização local de código.

Se a mudança reorganiza apenas ViewModels, Coordinators ou Reducers, sem alterar onde o domínio mora ou como pacotes se relacionam, você está escolhendo um pattern de apresentação, não redesenhando a arquitetura do sistema.

Arquitetura não é sinônimo de "muitas pastas"

É tentador acreditar que criar diretórios `Domain`, `Data`, `Presentation` automaticamente produz arquitetura. Pastas são vistas de desenvolvimento (Kruchten); só viram arquitetura quando as dependências compilam na direção certa. Um `Interactor` dentro de VIP que chama `URLSession` diretamente viola a mesma regra que um ViewModel inchado: fronteira fraca entre apresentação e infraestrutura. O nome do pattern não salva um grafo de imports invertido.

No EstudoPatterns, a prova está no compilador: módulos de apresentação importam `Shared` e `DesignSystem`, nunca o contrário. Essa é uma decisão arquitetural pequena, mas real, mais real do que rotular o app de "MVVM" no README.

Duas escalas, um mesmo app

O diagrama abaixo contrasta o que é estrutural (arquitetura no sentido amplo) com o que é variante de estudo (patterns) no EstudoPatterns:

Duas escalas no EstudoPatterns: decisões estruturais vs patterns de apresentação

A linha divisória não é dogmática: Shared e DesignSystem são decisões que se aproximam de arquitetura porque estabilizam o sistema enquanto os patterns de UI mudam. MVVM, MVVM-C, VIP e TCA são plug-ins pedagógicos na mesma tomada elétrica.

Por que os patterns do EstudoPatterns não são arquiteturas

O projeto implementa autenticação contra a API dev-challenge. Em todos os módulos de apresentação:

  • Domínio (`AuthCredentials`, `RegistrationForm`, `AuthToken`) vive em `Modules/Shared`.
  • Rede (`AuthRepository`, `AuthAPI`, MLNetworkLayer) também está em `Shared`.
  • UI reutilizável (`DSTextField`, `AuthStrings`, `AuthSuccessView`) está em `Modules/DesignSystem`.

O hub do app (`PatternHubView`) apenas escolhe qual módulo de apresentação abrir. Cada item descreve como o fluxo é organizado, não o que o sistema faz. Veja os subtítulos em `PatternItem.swift`:

  • MVVM: *"ViewModel concentra estado; navegação na View."*
  • MVVM-C: *"ViewModel emite eventos; Coordinator decide rotas."*
  • VIP: *"View, Interactor, Presenter; Router navega."*
  • TCA: *"Reducer + Store; fluxo unidirecional com efeitos."*

São diferenças de orquestração de interface, não de negócio.

Análise por pattern

MVVM

  • O que resolve: binding entre View e estado; ViewModel dispara efeitos de apresentação.
  • O que não define: onde ficam repositórios, política de rede, limites entre módulos.

MVVM-C

  • O que resolve: MVVM + Coordinator, pattern de navegação que desacopla transições de tela.
  • O que não define: estrutura de pacotes SPM, domínio, pipeline de CI.

VIP (Clean Swift)

  • O que resolve: papéis View, Interactor, Presenter e Router dentro de um fluxo.
  • O que não define: camadas globais; o Interactor aqui não é, por si só, a camada de Use Cases de Clean Architecture em todo o app.

TCA

  • O que resolve: fluxo unidirecional com `Action`, `Reducer`, `Effect` e novo estado (Point-Free, 2020+).
  • O que não define: infraestrutura; é biblioteca + pattern de gerência de estado na UI.

O argumento da substituibilidade

No EstudoPatterns, trocar o módulo MVVM pelo TCA não exige reescrever `AuthRepository`, modelos de domínio ou componentes do DesignSystem. Os testes de `Shared` continuam válidos; só mudam os testes da camada de apresentação (ViewModel, Coordinator, Presenter ou `TestStore`).

Se fossem arquiteturas mutuamente exclusivas no sentido forte, essa troca seria um *rewrite*. É uma troca de adapter de UI, exatamente o comportamento esperado quando a arquitetura base está bem separada dos patterns de apresentação.

Mapa de fluxo comparável

Mapa comparativo de fluxo: MVVM, MVVM-C, VIP e TCA

Repare: AuthRepository (ou seu cliente) aparece em todos os fluxos. O pattern desenha o caminho entre a View e o repositório; a arquitetura de dados permanece.

Confusões comuns na comunidade iOS

"Nosso app usa arquitetura MVVM"

A Apple documenta o MVC como padrão da camada Cocoa: models, views e controllers com papéis definidos no ecossistema (Apple Developer Documentation). MVVM emergiu na comunidade como adaptação do Presentation Model de Fowler para binding declarativo (SwiftUI, Combine, RxSwift). É uma convenção de apresentação amplamente adotada, não um documento normativo de arquitetura de sistema da plataforma.

"VIPER é a arquitetura do nosso banco / startup"

VIPER (e variantes como VIP/Clean Swift de Sutherland) impõem separação rígida por feature: View, Interactor, Presenter, Entity, Router. Isso melhora isolamento em codebases UIKit grandes, mas em apps reais VIPER convive com Coordinators, workers, módulos SPM e camadas de domínio compartilhadas. VIPER é um pattern modular por tela ou fluxo, não um mapa único do app, especialmente quando cada squad nomeia pastas de forma diferente.

"Adotamos TCA como arquitetura"

O Composable Architecture da Point-Free é uma biblioteca que implementa um pattern de estado unidirecional inspirado em Redux e Elm. Excelente para testabilidade de fluxos complexos (`TestStore`), mas apps maduros em TCA ainda separam Domain e Data; o reducer não substitui repositórios nem regras de negócio centrais. TCA é pattern + ferramenta, não um substituto automático de Clean Architecture.

"Coordinator é uma arquitetura"

O Coordinator (popularizado por Soroush Khanlou e amplamente documentado na comunidade Swift) resolve navegação: quem empurra qual tela, com quais dependências, sem acoplar view controllers ou views entre si. Matrizes de seleção de pattern, inclusive as usadas no EstudoPatterns, costumam classificá-lo na camada de navegação, não como arquitetura completa. MVVM-C no projeto é exatamente isso: MVVM mais pattern de navegação.

Por que a confusão persiste?

Três forças culturais explicam o hábito de dizer "arquitetura" quando queremos dizer "pattern":

  1. Marketing e vagas: "experiência em arquitetura X" cabe melhor em uma linha de currículo do que "experiência em pattern de apresentação X".
  2. Bootcamps e tutoriais: muitos ensinam MVVM como se fosse o esqueleto inteiro do app, porque é pedagógico começar pela tela.
  3. Fronteira móvel do POSA: alguns patterns de apresentação são descritos como "architectural" em livros, o que é tecnicamente defensável na escala de um subsistema de UI, mas vira ruído quando passamos a tratá-los como substitutos de domínio e dados.

Reconhecer essas forças não é purismo acadêmico: é ferramenta para estimar refactors. Migrar de MVVM para TCA no EstudoPatterns é trabalho de alguns arquivos em `Modules/TCA`. Migrar de um monólito acoplado para módulos com domínio isolado é trabalho de arquitetura, semanas ou meses, dependendo do tamanho do legado.

Quando faz sentido falar em arquitetura no seu app

Voltando ao EstudoPatterns, estas decisões já são arquiteturais no sentido útil do termo:

  1. Modularização via Swift Package Manager: `Shared`, `DesignSystem` e um módulo por pattern de apresentação. Isso define grafos de dependência, tempos de compilação e ownership por equipe.
  2. Fronteira domínio/dados: `AuthRepositoryProtocol` no Shared, implementação com MLNetworkLayer, DTOs `Sendable`, erros de domínio (`AuthError`). A apresentação depende de um contrato estável, não de detalhes HTTP.
  3. Design system compartilhado: tokens, strings e componentes comuns garantem que a comparação entre patterns seja justa e que a identidade visual não se fragmente.
  4. Hub de entrada único: o app shell não "é MVVM"; ele seleciona qual pattern estudar. A arquitetura do produto de estudo é "base comum + variantes plugáveis".

Próximos passos que reforçariam a arquitetura (sem mudar os patterns):

  • Use Cases explícitos na camada de domínio (`LoginUser`, `RegisterUser`).
  • Persistência de sessão (Keychain) atrás de uma porta no Shared.
  • Módulos por jornada de negócio (`Statement`, `Balance`) usando a mesma base.

Sugestão de nomenclatura

  • Evite: "Arquitetura MVVM". Prefira: "Pattern de apresentação MVVM".
  • Evite: "Vamos de VIPER no app". Prefira: "Pattern VIP por feature na camada de UI".
  • Evite: "O app é TCA". Prefira: "A UI usa TCA; domínio e dados estão em…".
  • Evite: "Qual arquitetura é melhor?". Prefira: "Qual pattern de apresentação se encaixa neste fluxo e nesta equipe?".

Precisão de linguagem reduz debates falsos. MVVM e TCA não competem como "arquiteturas rivais" se ambos consomem o mesmo `AuthRepository`.

Conclusão

Patterns e arquitetura não são inimigos: operam em escalas diferentes. Patterns respondem a problemas recorrentes em um contexto delimitado. Arquitetura organiza o sistema inteiro: módulos, dependências, domínio, infraestrutura e as qualidades que você não pode colar depois com um refactor de ViewModel.

O EstudoPatterns existe para tornar essa distinção visível no código: a mesma autenticação, o mesmo repositório, os mesmos botões, quatro formas de conduzir estado e navegação na interface. Isso não prova que MVVM seja "pior" ou que TCA seja "melhor". Prova que são intercambiáveis na camada em que atuam, desde que a base arquitetural esteja sólida.

Na próxima vez que alguém propor "mudar a arquitetura do app para X", vale perguntar: estamos mudando como o sistema inteiro se estrutura, ou apenas como as telas organizam estado e eventos? A resposta honesta economiza meses de migração desnecessária.

Para experimentar na prática, clone o repositório swift-patterns-studies, abra o hub de patterns e compare os fluxos lado a lado. O guia técnico Comparação Auth entre patterns detalha quem navega, quem chama a API e como testar cada módulo.

Referências bibliográficas

  1. GAMMA, E.; HELM, R.; JOHNSON, R.; VLISSIDES, J. *Design Patterns: Elements of Reusable Object-Oriented Software*. Addison-Wesley, 1994.
  2. BUSCHMANN, F. et al. *Pattern-Oriented Software Architecture, Volume 1: A System of Patterns*. Wiley, 1996.
  3. FOWLER, M. *Patterns of Enterprise Application Architecture*. Addison-Wesley, 2002. (Capítulo *Presentation Model*.)
  4. FOWLER, M. Presentation Model. Disponível em: https://martinfowler.com/eaaDev/PresentationModel.html. Acesso em: 10 jun. 2026.
  5. MARTIN, R. C. *Clean Architecture: A Craftsman's Guide to Software Structure and Design*. Prentice Hall, 2017.
  6. BASS, L.; CLEMENTS, P.; KAZMAN, R. *Software Architecture in Practice*. 3. ed. Addison-Wesley, 2012.
  7. KRUCHTEN, P. The 4+1 View Model of Architecture. *IEEE Software*, v. 12, n. 6, p. 42-50, 1995.
  8. APPLE INC. Cocoa Application Layer / Model-View-Controller. Documentação para desenvolvedores. Disponível em: https://developer.apple.com/documentation/. Acesso em: 10 jun. 2026.
  9. SUTHERLAND, R. Clean Swift (VIP). Disponível em: https://clean-swift.com. Acesso em: 10 jun. 2026.
  10. POINT-FREE. Composable Architecture. Repositório GitHub. Disponível em: https://github.com/pointfreeco/swift-composable-architecture. Acesso em: 10 jun. 2026.
  11. MICHEL TLUTZ. swift-patterns-studies: repositório e comparação da jornada Auth entre patterns. Disponível em: https://github.com/micheltlutz/swift-patterns-studies e docs/patterns/auth-comparison.md. Acesso em: 10 jun. 2026.