このシリーズに沿ってモジュールを数十個まで増やしたチームは、やがて新しい種類の疲労に直面します。
モジュールを追加するたびに繰り返す設定作業、残り続けるプロジェクトファイルの競合、そしてメンバーごとに少しずつ異なるモジュール構成です。
Tuistはまさにこの問題を狙うツールです。一言でいえば、Xcodeプロジェクトファイルをリポジトリからなくし、Swiftコードによる宣言から生成します。
この記事では、Tuistが解決する問題、Project.swiftの基本、そして大規模チームで真価を発揮するバイナリーキャッシュまで整理します。2026年7月時点のTuist 4が基準です。
Tuistはどのような問題を解決しますか?
ポイントは、pbxprojの所有権を人からツールへ移すことです。
一般的なiOSプロジェクトでは、project.pbxprojをリポジトリにコミットします。ファイル追加やターゲット設定の変更はすべてこのファイルに影響しますが、形式も人間には読みにくいため、マージ競合の解消は厄介です。
Tuistプロジェクトでは、このファイルをコミットしません。代わりにProject.swiftの宣言をコミットします。
| 比較 | 一般的なプロジェクト | Tuistプロジェクト |
|---|---|---|
| リポジトリにあるもの | project.pbxproj | Project.swift(Swiftコード) |
| プロジェクトファイル | 手動で管理 | tuist generateで毎回生成 |
| マージ競合 | pbxprojで頻発 | Swiftコードの差分なのでまれ |
| モジュール追加 | GUI操作+設定の繰り返し | 関数呼び出し1行 |
プロジェクトファイルが生成物になった瞬間、マージ競合の対象から外れます。.gitignoreに入れれば完了です。
Project.swiftはどのような形ですか?
モジュール定義がSwiftコードなので、繰り返す構成を関数にまとめられる点が大きな魅力です。
// 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"),
]
),
]
)
ここまではSPM(Swift Package Manager)のPackage.swiftに似ています。違いは拡張性にあります。
チーム標準のモジュール構成をヘルパー関数として定義しておけば、新しい機能モジュールの追加が本当に1行になります。
// チーム標準:機能モジュール=ソース + テスト + デモアプリ一式
let searchModule = Target.featureModule(name: "Search")
let orderModule = Target.featureModule(name: "Order")
// モジュールあたりのターゲット数。設定はヘルパー内で統一 3
モジュールが30個ある場合、pbxproj方式では設定画面を30回繰り返しますが、Tuistでは配列に名前を追加するだけです。メンバーごとの設定ずれもなくなります。
依存グラフの可視化も組み込まれています。tuist graphコマンド1つでモジュールの依存関係を図にでき、循環依存や前回警告した「全員が依存する肥大化モジュール」も目で確認できます。
バイナリーキャッシュ、ビルド速度の次の段階
前回はモジュール化によって再コンパイル範囲を減らせると説明しましたが、Tuistのキャッシュはさらに一歩進みます。
tuist cacheは各モジュールを事前ビルドし、バイナリー(フレームワーク)として保存します。その後tuist generateを実行すると、変更されていないモジュールはソースではなくキャッシュ済みバイナリーに置き換わります。
- 検索機能だけを開発しているなら、検索モジュールだけをソースで開き、残り数十個のモジュールはビルド済みバイナリーで受け取ります
- クリーンビルドでさえ、実質的に「自分のモジュール+リンク」だけになります
リモートキャッシュを使えば、これらのバイナリーをチームとCIで共有できます。同僚がすでにビルドしたモジュールを自分のマシンで再ビルドする必要はありません。大規模チームでクリーンビルドが分単位から秒単位になった事例が出る理由です。
いつ導入し、いつ過剰になりますか?
Tuistは強力ですが、チーム必須の依存関係として1つのツールを追加する決断でもあります。
| 状況 | 判断 |
|---|---|
| モジュール10個未満、小規模チーム | SPMのローカルパッケージで十分 |
| モジュール数十個、pbxprojの競合が毎週発生 | 導入する価値が大きい |
| CI・チームのビルド時間がコスト問題になる | キャッシュだけでも導入の根拠として十分 |
| チームにビルドシステム担当の余力がまったくない | 学習コストとアップデート追従コストを考慮 |
導入するなら全面移行より、新規モジュールからTuistで管理し、既存ターゲットを段階的に移行する方が安全です。プロジェクト生成だけを担う、より軽量な代替案XcodeGenもあるので、キャッシュが不要なら併せて検討してください。
面接ではこう聞かれます
Q. Tuistのようなプロジェクト生成ツールを導入する理由は何ですか?
pbxprojをリポジトリから除いてマージ競合をなくし、プロジェクト構成をSwiftコードで宣言してモジュールテンプレートを標準化できるからです。さらにバイナリーキャッシュで変更のないモジュールの再ビルドを省き、モジュール化の管理コストを下げながらビルド速度の利点を高められます。
Q. モジュールが増えたとき、チーム全体でビルド時間を短縮する方法を説明してください。
モジュール単位のバイナリーキャッシュを導入し、変更のないモジュールをビルド済み成果物に置き換え、リモートキャッシュでチームとCIに共有します。開発者は作業中のモジュールだけをソースで開くため、クリーンビルドのコストが作業範囲に比例します。
これでモジュール化シリーズを終えます。境界と凝集度から始まり、依存方向、レイヤー構造、SPM、ビルド速度、そしてTuistまで扱ってきました。
順番に適用していけば、「ビルドが速くなった」だけでなく、「変更するのが怖くないコードベース」という、より大きな成果を得られるはずです。

![[モジュール化 #6] TuistでiOSのモジュール化が楽になる理由(pbxprojの競合・バイナリーキャッシュ)のカバー画像](/assets/images/posts/2461e64e-988b-43c4-a75f-59b167bfa642/1.jpg)