[譯] 在 iOS 上使用 Carthage 建立依賴
在本文中,我想通過使用 Carthage 分享構建依賴關係的經驗。Carthage 簡潔明瞭,只需在Cartfile
中新增適當的內容並執行carthage update
就可以在 Xcode 專案中使用一些外部依賴項。但眾所周知的是,現實是殘酷的,有時我們需要考慮更加複雜的例子。
我們假設有一個 iOS 開發團隊。Tony、John 和 Keith 都正在使用大約15個 流行的第三方依賴庫,如 Alamofire、Kingfisher、ReactiveCocoa 等。
他們可能會遇到的問題
- 不同的編譯器 - 一些庫是用 Swift 編寫的,這意味著每個不同的編譯器執行時都與其他編譯器不相相容。如果這些開發人員使用不同版本的 Xcode,這可能產生一個巨大的問題,他們每個人都需要構建自己的框架版本或使用相同版本的 Xcode。
- 清理編譯時間 - 這是最近的熱門話題,有時我們需要關心編譯時間,特別是在 CI 和分支之間切換時。一個團隊就意味著他們不想用 1 小時或者更久來浪費在等待發布上,因此這個問題可能很關鍵。
- 倉庫大小 - 一些開發者更喜歡在倉庫下包含已編譯好的框架。假設這個團隊正在使用免費的 GitHub 計劃,因此他們的倉庫最大為 1 GB。在倉庫中儲存別的框架可能導致其大小大幅增加,甚至可能有 5 GB。即使倉庫儲存限制不是問題,克隆這樣的倉庫也需要花費相當多的時間 。這可能會對清理編譯時間產生巨大影響,尤其是在將 CI 與虛擬機器一起使用時。
-
更新框架
- 當你執行
carthage update
,如果沒有別的額外工作,carthage 將重新編譯所有 框架。在專案開始時,我們會經常這樣做。團隊正在尋找一種更快速的解決方案。
天下沒有免費的午餐我同意,但是同時我相信有時候你花一些時間來改善你的日常用到的工具是很值得的。我花了很多時間 試驗依賴庫管理器,甚至是快取他們產生的依賴庫等等。下面讓我告訴你三個維護 carthage 框架的流行解決方案把。
在你開始之前
- 如果您不熟 Carthage,請首先看看它的目錄 。
- 我不會考慮直接在專案倉庫中直接儲存 Carthage 框架。
簡單的方法
故事開始了,Tony 是團隊領導,他決定使用 Carthage 來管理依賴庫,他在使用外部框架時為其他開發者定義了一些規則:
-
把
Carthage/Build
和Carthage / Checkouts
新增到.gitignore
-
第一次克隆倉庫時,你需要執行
carthage bootstrap
來重建所有依賴項。在 CI 中則需要為每個管道執行。 -
更新框架時,只更新一個,例如
carthage update ReactiveSwift
。
這些都是非常簡單的規則,但是它們的優缺點如何呢?
優點:
- 完全免費
- 倉庫大小不會迅速增加
缺點:
- 清理編譯時間很長
- 絕對不會重複使用預編譯的框架
- 你的倉庫中的將多出其他程式碼
讓我們將此解決方案與可能出現的問題進行比較:
問題 | 已經解決? | 還缺少什麼? |
---|---|---|
不同的編譯器 | 否 | 所有開發者的編譯器版本必須相同 |
清理編譯時間 | 是 | CI 將只會編譯程式部分的程式碼並且為每個管道重用預編譯好的所有依賴庫 |
倉庫大小 | 是 | - |
更新框架 | 否 | 沒有改善,開發者需要在升級時重新編譯框架和依賴庫 |
總結一下,這種方法的最大的問題是時間 。唯一完全解決的問題是倉庫的大小。CI 編譯時間非常長,並且會隨著依賴項的數量相應地增長。正如你所看到的,還有很多需要改進的地方。讓我們嘗試不同的解決方案吧!
Git 裡的 LFS
有一天一個開發者 John 發現了 GitHub 允許在它們的 LFS(大檔案儲存系統)下儲存很大的檔案。他意識到這可能是一個很好的機會,來把預編譯的框架放到 git 倉庫裡下,同時保證了倉庫還是比較小的。他把 Tony 的規則做了一點店修改:
-
同時
把
Carthage/Build
和Carthage/Checkouts
新增到.gitignore
, -
當第一次克隆倉庫的時候,你不必
執行
carthage bootstrap
來重新編譯所有依賴,但是你需要從 LFS 裡抽取框架, -
當更新框架時,請使用例如
carthage update ReactiveSwift
來更新,還有一些工作需要做 ,你需要把那些框架歸檔,新增至.gitattributes
,壓縮並上傳到 LFS, - 所有的專案組成員 必須保持 Xcode 和 Swit 的版本一致。
這個解決方案更加複雜,因為需要額外的壓縮和上傳框架的操作。這裡有一篇很好的文章,它提供了詳細的操作講解並提供了一些原始的Makefile
,可以讓這些操作自動進行。
優點;
- 倉庫的大小仍然沒有增加
- 只需要克隆倉庫後再提取框架
缺點:
- 大部分情況下不免費(1 GB 的 LFS 每月需要 5 美元)
- 所有的開發者 Xcode 版本必須相同
- 沒有使框架更新加快的機制
讓我們比較一下這個方案所能解決的問題和文章開頭提出的問題:
問題 | 已經解決? | 還缺少什麼? |
---|---|---|
不同的編譯器 | 部分解決 | 如果兩個開發者使用相同的 Xcode,他們都需要重新編譯 |
清理編譯時間 | 否 | 編譯將持續很長時間,每次都會把 CI 上的所有依賴重新編譯 |
倉庫大小 | 是 | - |
更新框架 | 否 | 沒有改善,開發者需要在升級時重新編譯框架和依賴庫 |
畢竟我認為這看起來好多了!對於大多數團隊而言,快速清理構建相比於在開發者之間可能使用不同 Xcode 來說更為重要。他們仍然可以安裝不同的版本,只在特定專案之間切換。我相信每月 5 美元的 LFS 並不算貴。所以這是一個更好,同時也更難的解決方案,但仍有一些改進空間...
Rome
現在 Keith 又出現了,他很欣賞其他開發者的研究,但 Keith 非常在意團隊合作。他認為也許可以在不同專案之間共享由不同版本的 Swift 編譯器預編譯的不同版本的框架,這種情況很多,但幸運的是有這樣一個工具!它被稱為Rome
。我強烈建議您檢視相關文件
。通常此工具使用 Amazon S3 Bucket 來共享框架,Keith 再一次地改變了規則:
-
把
Carthage/Build
和Carthage/Checkouts
都 新增到.gitignore
, -
當第一次克隆倉庫的時候,當第一次克隆倉庫的時候,你不必
執行
carthage bootstrap
來重新編譯所有依賴,但是你需要從 Amazon S3 上下載它們, -
當更新框架時,請使用例如
carthage update ReactiveSwift --no-build
僅僅更新一個框架版本 ,嘗試從 Amazon 下載它,並且如果它不存在的話就把它編譯並上傳, -
你需要定義
RepositoryMap
來告訴 Rome 你使用了哪一個由 Carthage 編譯的依賴。
通過使用一些非常簡單的
的輔助指令碼,這些規則幾乎與一開始天真的方法
中的規則一樣簡單。我對此工具的印象非常深刻,尤其是僅限的一些步驟帶來了顯著的成效,下面來讓我們看看這個解決方案的優缺點:
優點:
RepositoryMap
缺點:
-
不免費,但是仍然比LFS
(
$0.023 / GB
) 便宜
和上一個解決方案相比:
問題 | 已經解決? | 還缺少什麼? |
---|---|---|
不同的編譯器 | 是 | - |
清理編譯時間 | 是 | - |
倉庫大小 | 是 | - |
更新框架 | 是 | - |
在我看來這個解決方案將為你在依賴管理上節省大量時間,當然有時你將需要在你自己的電腦或是 CI 上編譯,但是你需要保證此工作會被重用。
回顧
所以你應該已經意到我相信 Rome 才是目前最好的解決方案,我強烈建議你使用它,但以上的故事表明總有一些東西是可以進行改進的。你應該嘗試不同的方法並選擇最佳解決方案。我相信在閱讀 Tony,John 和 Keith 的故事時,你注意到的不僅僅是 Rome 是 Carthage 的最佳搭檔,還應該聯絡到團隊工作和工作流程的改進。CI 做為虛擬的第四位團隊成員,其他幾個人一直試圖解協作開發的問題,最後他們中的一個找到了一個理想的解決方案來滿足他們的需求。