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.
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.
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.

![Imagem de capa de [Modularização #6] Modularização iOS fácil com Tuist](/assets/images/posts/2461e64e-988b-43c4-a75f-59b167bfa642/1.jpg)