核心理念#

持續整合(Continuous Integration, CI)是一種開發實踐,要求開發者頻繁地將程式碼整合到主幹(trunk),通常每天至少一次。每次整合都透過自動化建構和測試來驗證,從而儘早發現整合錯誤。

CI 的根本目標是讓「整合」不再是一個大型、痛苦、充滿風險的事件,而是日常開發流程中的一個微小、頻繁、低風險的活動。

小批量開發與大批量合併的對比#

大批量合併的問題#

傳統的開發方式中,開發者在各自的 feature branch 上工作數天、數週甚至數月,最後才嘗試將所有人的程式碼合併在一起。這種做法會導致:

  • 合併地獄(merge hell):大量程式碼衝突需要解決
  • 發現問題的時間延遲:整合問題直到合併時才浮現
  • 風險集中:所有風險集中在合併階段
  • 除錯困難:當出問題時,需要在大量變更中尋找原因

小批量整合的優勢#

頻繁的小批量整合帶來完全不同的體驗:

  • 衝突最小化:每次只整合少量變更,衝突容易解決
  • 快速回饋:問題在引入後幾分鐘內就被發現
  • 風險分散:風險均勻分佈在每次提交中
  • 除錯簡單:問題範圍限縮在最近的少量變更中

持續整合要求開發者至少每天將程式碼整合到主幹。分支的存活時間越長,合併的難度越高,風險越大。

基於主幹的開發(Trunk-Based Development)#

基於主幹的開發是實踐持續整合的基礎。其核心原則包括:

  • 所有開發者都在主幹(trunk/main)上工作,或使用存活時間極短的分支
  • 分支的壽命不超過一天
  • 禁止長期存在的 feature branch
  • 程式碼在合併前必須通過所有自動化測試

如果你的團隊有存活超過一天的分支,那就不是在真正地實踐持續整合。

持續整合的前提條件#

要成功實踐 CI,團隊需要具備以下條件:

  1. 全面的自動化測試套件:確保每次提交都能被快速驗證
  2. 所有內容在版本控制中:程式碼、設定、測試、環境定義
  3. 維持建構綠燈的紀律:當建構失敗時,修復它是最高優先事項
  4. 短小的提交:每次提交的變更量要小,便於審查和除錯
  5. 共同所有權:任何人都可以修改任何程式碼

持續整合的實踐#

保持建構快速#

建構時間直接影響回饋速度和開發者的生產力:

  • 目標:建構和測試在幾分鐘內完成(理想情況下 10 分鐘以內)
  • 策略:並行測試、分層測試、增量建構
  • 如果完整建構需要很長時間,可以先執行快速測試(commit stage),再異步執行慢速測試

當建構失敗時立即修復#

這是 CI 最關鍵的紀律:

  • 建構失敗 = 停止生產線:就像豐田生產系統的安燈(andon cord)
  • 引入失敗的開發者必須立即修復,或回退(revert)變更
  • 在建構修復之前,禁止任何人提交新程式碼到主幹
  • 如果建構經常失敗而無人修復,團隊會失去對 CI 的信任

忽略失敗的建構是最危險的反模式之一。一旦團隊習慣了紅色建構,CI 就名存實亡。

不要將失敗的測試註解掉#

當測試失敗阻擋了進度時,開發者可能會想把測試註解掉或跳過。這是一個必須抵制的誘惑:

  • 被註解掉的測試永遠不會被修復
  • 它代表的功能驗證從此消失
  • 正確的做法是修復測試或修復程式碼

Gated Commits(門控提交)#

為了防止壞掉的程式碼進入主幹,可以使用 gated commits(門控提交)機制:

  • 程式碼在合併到主幹前,先在獨立環境中建構和測試
  • 只有通過所有測試的變更才能被合併
  • 這確保了主幹始終處於可部署狀態
  • 許多現代 CI 系統(如 GitHub Actions、GitLab CI)原生支持此模式

持續整合與 Feature Branch 的衝突#

長期存在的 feature branch 與持續整合是矛盾的:

  • Feature branch 延遲了整合,增加了合併風險
  • 開發者在分支上工作越久,與主幹的差異越大
  • 合併時可能面臨大量衝突和意外的行為變更

替代方案包括:

  • Feature toggles(功能開關):在主幹中開發新功能,但透過開關控制是否對使用者可見
  • Branch by abstraction:透過抽象層逐步替換實作
  • Dark launching:將新功能部署到生產環境但不對外開放

Feature toggles 讓我們能夠將「部署」和「發布」解耦——程式碼可以部署到生產環境,但功能可以在不同時間點對不同使用者啟用。

持續整合的文化面向#

CI 不僅是技術實踐,更是一種團隊文化

  • 集體責任:整個團隊對建構的健康負責
  • 透明度:建構狀態對所有人可見(build radiator)
  • 互相幫助:當建構失敗時,不是指責,而是協助修復
  • 持續改善:定期回顧和優化建構流程

環境一致性#

持續整合的另一個關鍵面向是確保 CI 環境與生產環境盡可能一致:

  • CI 伺服器應使用與生產環境相同的作業系統和設定
  • 依賴的服務版本應該一致
  • 環境差異是許多「在我的機器上可以運行」問題的根源

結論#

持續整合是實現快速流動的基礎實踐。透過要求開發者每天將程式碼整合到主幹、維持快速且可靠的自動化建構、以及在建構失敗時立即修復,我們確保了程式碼始終處於可部署狀態。這為後續的持續交付和持續部署奠定了堅實的基礎,使團隊能夠安全且頻繁地向客戶交付價值。