Design de software

[Modularização #6] Modularização iOS fácil com Tuist

Equipes que ampliaram os módulos para algumas dezenas ao longo desta série acabam encontrando um novo tipo de cansaço.

4 min de leitura
Imagem de capa de [Modularização #6] Modularização iOS fácil com Tuist

Equipes que ampliaram os módulos para algumas dezenas ao longo desta série acabam encontrando um novo tipo de cansaço.

Configurações repetidas a cada módulo, conflitos persistentes nos arquivos do projeto e configurações sutilmente diferentes entre os membros da equipe.

O Tuist resolve exatamente esse problema. Em resumo, ele remove os arquivos de projeto do Xcode do repositório e os gera a partir de código Swift declarativo.

Este artigo aborda os problemas resolvidos pelo Tuist, o uso básico de Project.swift e o cache de binários para equipes grandes. Com base no Tuist 4, em julho de 2026.


Que problemas o Tuist resolve?

O ponto central é transferir a responsabilidade pelo pbxproj das pessoas para uma ferramenta.

Em um projeto iOS típico, project.pbxproj é commitado no repositório. Adicionar arquivos e alterar configurações de targets modifica esse arquivo, cujo formato é difícil de ler; por isso, resolver conflitos de merge é trabalhoso.

Em projetos Tuist, esse arquivo não é commitado. Em vez disso, você commita uma declaração chamada Project.swift.

Comparação Projeto comum Projeto Tuist
No repositório project.pbxproj Project.swift (código Swift)
Arquivo do projeto Gerenciado manualmente Gerado sempre com tuist generate
Conflitos de merge Frequentes no pbxproj Raros com diffs de código Swift
Adicionar um módulo Operações na GUI + configurações repetidas Uma chamada de função

Quando o arquivo do projeto se torna um artefato gerado, ele deixa de ser alvo de conflitos de merge. Basta adicioná-lo ao .gitignore.


Como é o Project.swift?

O destaque é que as definições dos módulos são código Swift, então configurações repetidas podem ser agrupadas em funções.

// Project.swift
let project = Project(
    name: "MyApp",
    targets: [
        .target(
            name: "MyApp",
            destinations: .iOS,
            product: .app,
            bundleId: "com.example.myapp",
            sources: ["Sources/**"],
            dependencies: [
                .target(name: "FeatureSearch"),
                .target(name: "CoreNetwork"),
            ]
        ),
    ]
)

Até aqui, ele pode parecer com o Package.swift do SPM (Swift Package Manager). A diferença está na extensibilidade.

Defina o formato padrão de módulo da equipe em uma função auxiliar, e adicionar um novo módulo de funcionalidade realmente vira uma linha.

// Padrão da equipe: módulo de funcionalidade = conjunto de + testes + aplicativo demo
let searchModule = Target.featureModule(name: "Search")
let orderModule = Target.featureModule(name: "Order")
// targets por módulo; configurações unificadas dentro da função auxiliar 3

Com 30 módulos, a abordagem com pbxproj exige repetir a tela de configurações 30 vezes; com o Tuist, basta adicionar um nome a um array. A possibilidade de configurações divergentes entre membros da equipe também desaparece.

A visualização do grafo de dependências já vem integrada. Um único comando tuist graph desenha as dependências entre módulos, facilitando identificar dependências circulares ou o “módulo inchado do qual todos dependem” mencionado no artigo anterior.

Fluxo da declaração até o projeto gerado
Fluxo da declaração até o projeto gerado

Cache de binários: o próximo passo para acelerar o build

No artigo anterior, vimos que a modularização reduz o escopo da recompilação; o cache do Tuist vai além.

tuist cache faz o build antecipado de cada módulo e o armazena como binário (framework). Durante o tuist generate, módulos inalterados são substituídos por binários em cache, em vez do código-fonte.

  • Se estou desenvolvendo apenas a funcionalidade de busca: abro o módulo de busca como código-fonte e recebo os outros módulos como binários já compilados.
  • Até um clean build, na prática, fica reduzido a “meu módulo + linking”.

Com um cache remoto, a equipe e o CI compartilham esses binários. Minha máquina não recompila um módulo que um colega já compilou. É por isso que equipes grandes relatam reduzir o tempo de clean build de minutos para segundos.


Quando adotar e quando é exagero?

O Tuist é poderoso, mas adotá-lo também transforma mais uma ferramenta em dependência obrigatória da equipe.

Situação Avaliação
Menos de 10 módulos, equipe pequena Pacotes locais do SPM são suficientes
Dezenas de módulos, conflitos semanais no pbxproj Grande valor na adoção
O tempo de build do CI e da equipe vira um problema de custo O cache, por si só, já justifica a adoção
A equipe não tem nenhuma disponibilidade para cuidar do sistema de build Considere a curva de aprendizado e o custo de acompanhar atualizações

Se adotar, comece gerenciando os módulos novos com Tuist e migre os targets existentes gradualmente, em vez de mudar tudo de uma vez. XcodeGen é uma alternativa mais leve, responsável apenas pela geração do projeto; avalie-o também se não precisar de cache.

Como isso aparece em entrevistas

P. Por que adotar uma ferramenta de geração de projetos como o Tuist?

Porque remover o pbxproj do repositório elimina conflitos de merge, e declarar a configuração do projeto em código Swift permite padronizar templates de módulos. Além disso, o cache de binários evita recompilar módulos inalterados, reduzindo o custo de gerenciamento da modularização e ampliando o ganho de velocidade no build.

P. Como você reduziria o tempo de build da equipe à medida que o número de módulos cresce?

Adote cache de binários por módulo para substituir módulos inalterados por artefatos pré-compilados e compartilhe-os entre a equipe e o CI por meio de um cache remoto. Os desenvolvedores abrem como código-fonte apenas o módulo em que trabalham, fazendo o custo do clean build acompanhar o escopo do trabalho.

Deixar o grafo de dependências na tela agiliza a conversa
Deixar o grafo de dependências na tela agiliza a conversa

Com isso, encerramos a série sobre modularização. Começamos com limites e coesão, passamos por direção das dependências, estrutura em camadas, SPM e velocidade de build, até chegar ao Tuist.

Aplicando esses passos em ordem, você ganha mais do que “builds mais rápidos”: uma base de código que deixa de ser assustadora para modificar.