軟體設計

[模組化 #6] Tuist 讓 iOS 模組化更容易的原因(pbxproj 衝突・二進位快取)

如果團隊依照這個系列,已將模組增加到數十個,就會遇到一種新的疲勞。

閱讀 4 分鐘
[模組化 #6] Tuist 讓 iOS 模組化更容易的原因(pbxproj 衝突・二進位快取) 封面圖

如果團隊依照這個系列,已將模組增加到數十個,就會遇到一種新的疲勞。

每新增一個模組就要重複設定、專案檔衝突仍然存在,以及每位成員的模組組態略有不同。

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 操作+重複設定 一行函式呼叫

專案檔成為產生物後,就不再是合併衝突的對象。加入 .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 很像,差異在於可擴充性。

先用輔助函式定義團隊標準的模組形式,新增功能模組真的只需一行。

// 團隊標準:功能模組=原始碼 + 測試 + 示範 App 組合
let searchModule = Target.featureModule(name: "Search")
let orderModule = Target.featureModule(name: "Order")
// 每個模組的目標 3個,設定統一放在輔助函式中

如果有 30 個模組,pbxproj 方式要重複 30 次設定畫面;Tuist 則只需在陣列中加入名稱,也消除了成員之間組態不一致的空間。

內建依賴圖視覺化功能。只要執行 tuist graph,就能繪出模組依賴關係,方便找出循環依賴,或看見上一篇警告的「所有人都依賴的肥大模組」。

從宣告產生專案的流程
從宣告產生專案的流程

二進位快取:提升建置速度的下一步

上一篇提到模組化能縮小重新編譯範圍,而 Tuist 快取更進一步。

tuist cache 會預先建置各模組,並以二進位檔(框架)儲存。之後執行 tuist generate 時,未變更的模組會以快取二進位檔取代原始碼。

  • 如果我只在開發搜尋功能:只將搜尋模組以原始碼開啟,其餘數十個模組則使用已完成建置的二進位檔
  • 就連清理建置實際上也只剩下「我的模組+連結」

使用遠端快取後,團隊與 CI 可以共用這些二進位檔。我的機器不必重新建置同事已經建置過的模組。大型團隊的清理建置時間能從數分鐘降到數秒,原因就在這裡。


何時該導入,何時會過度?

Tuist 很強大,但這也代表要將一個工具加入團隊的必要相依項目。

情況 判斷
少於 10 個模組、小型團隊 SPM 本機套件已足夠
數十個模組、每週都發生 pbxproj 衝突 導入價值高
CI 與團隊建置時間演變成成本問題 光是快取就足以成為導入理由
團隊完全沒有餘力負責建置系統 考量學習曲線與追蹤更新的成本

如果要導入,比起全面切換,更安全的做法是先以 Tuist 管理新模組,再逐步遷移既有目標。XcodeGen 是更輕量、只負責產生專案的替代方案;如果不需要快取,也可以一併評估。

面試時可以這樣問

Q. 為什麼要導入 Tuist 這類專案產生工具?

因為可以將 pbxproj 從儲存庫移除,消除合併衝突,並以 Swift 程式碼宣告專案組態,標準化模組範本。此外,二進位快取能跳過未變更模組的重新建置,降低模組化的管理成本並放大建置速度的優勢。

Q. 模組增加時,請說明如何從團隊層級縮短建置時間。

導入模組層級的二進位快取,將未變更模組替換成預先建置的產物,再透過遠端快取讓團隊與 CI 共用。開發者只需將自己工作的模組以原始碼開啟,清理建置成本便會與工作範圍成正比。

將依賴圖顯示在畫面上,能讓討論更快
將依賴圖顯示在畫面上,能讓討論更快

模組化系列到此告一段落。我們從邊界與內聚力開始,走過依賴方向、分層結構、SPM、建置速度,最後來到 Tuist。

依序套用後,除了「建置變快」,你還會得到更大的回報:一個不再害怕修改的程式碼基底。