Monorepositório com Swift: organização de código na prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Monorepositório com Swift: organização de código na prática

\n\n

O desenvolvimento iOS moderno enfrenta cada vez mais o desafio de escalar a base de código. Quando um projeto cresce para dezenas de módulos, bibliotecas compartilhadas e vários aplicativos (iOS, macOS, watchOS), o modelo tradicional com repositórios separados (polyrepo) começa a desacelerar o desenvolvimento. O monorepositório vem em socorro — um repositório único que contém o código de todos os componentes do ecossistema. Neste artigo, vamos analisar na prática como organizar um monorepositório para projetos Swift, usando ferramentas modernas: Swift Package Manager (SPM), Tuist e pipelines CI/CD eficientes.

\n\n

1. Por que um monorepositório no ecossistema Swift?

\n\n

Antes de mergulhar na implementação, é importante entender as principais vantagens da abordagem:

\n\n
    \n
  • Versionamento unificado — todos os módulos e aplicativos estão em um único commit, eliminando o problema do "inferno das dependências" (dependency hell).
  • \n
  • Refatoração simplificada — uma alteração de API em uma biblioteca é imediatamente visível para todos os consumidores; o compilador destacará erros dentro de um único PR.
  • \n
  • Navegação transparente — os desenvolvedores veem todo o código do projeto, sem precisar alternar entre repositórios.
  • \n
  • Otimização de CI/CD — é possível configurar a compilação apenas dos módulos alterados (targeted builds), economizando tempo e recursos.
  • \n
\n\n

No entanto, um monorepositório exige disciplina: uma arquitetura modular clara e ferramentas que evitem o caos. Para Swift, a melhor escolha hoje é o Tuist — um utilitário que gerencia projetos Xcode de forma declarativa, ou o puro Swift Package Manager para uma estrutura modular.

\n\n

2. Estrutura do monorepositório com Swift Package Manager

\n\n

Vamos começar com a organização básica. Suponha que temos dois aplicativos: MyAppiOS e MyAppMacOS, além de um conjunto de bibliotecas internas. A estrutura de diretórios pode ser assim:

\n\n
Monorepo/\n├── Apps/\n│   ├── MyAppiOS/\n│   │   ├── Sources/\n│   │   └── Package.swift (ou project.yml para Tuist)\n│   └── MyAppMacOS/\n│       ├── Sources/\n│       └── Package.swift\n├── Libraries/\n│   ├── Networking/\n│   │   ├── Sources/\n│   │   └── Package.swift\n│   ├── UIComponents/\n│   │   ├── Sources/\n│   │   └── Package.swift\n│   └── Core/\n│       ├── Sources/\n│       └── Package.swift\n├── Tests/\n│   ├── NetworkingTests/\n│   └── UIComponentsTests/\n├── Package.swift (manifesto raiz)\n└── Tuist/ (se estivermos usando Tuist)\n    └── Project.swift\n
\n\n

O Package.swift raiz conecta tudo. Exemplo de manifesto:

\n\n
// swift-tools-version:5.9\nimport PackageDescription\n\nlet package = Package(\n    name: "MyMonorepo",\n    platforms: [\n        .iOS(.v16), .macOS(.v13)\n    ],\n    products: [\n        .library(name: "Networking", targets: ["Networking"]),\n        .library(name: "UIComponents", targets: ["UIComponents"]),\n        .library(name: "Core", targets: ["Core"]),\n        .executable(name: "MyAppiOS", targets: ["MyAppiOS"]),\n        .executable(name: "MyAppMacOS", targets: ["MyAppMacOS"])\n    ],\n    dependencies: [\n        // Dependências externas\n        .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.8.0")\n    ],\n    targets: [\n        .target(\n            name: "Networking",\n            dependencies: ["Core", .product(name: "Alamofire", package: "Alamofire")],\n            path: "Libraries/Networking/Sources"\n        ),\n        .target(\n            name: "UIComponents",\n            dependencies: ["Core"],\n            path: "Libraries/UIComponents/Sources"\n        ),\n        .target(\n            name: "Core",\n            path: "Libraries/Core/Sources"\n        ),\n        .executableTarget(\n            name: "MyAppiOS",\n            dependencies: ["Networking", "UIComponents"],\n            path: "Apps/MyAppiOS/Sources"\n                

Blogs

Book Recommendations