核心理念#
持續整合(Continuous Integration, CI)是一種開發實踐,要求開發者頻繁地將程式碼整合到主幹(trunk),通常每天至少一次。每次整合都透過自動化建構和測試來驗證,從而儘早發現整合錯誤。
CI 的根本目標是讓「整合」不再是一個大型、痛苦、充滿風險的事件,而是日常開發流程中的一個微小、頻繁、低風險的活動。
小批量開發與大批量合併的對比#
大批量合併的問題#
傳統的開發方式中,開發者在各自的 feature branch 上工作數天、數週甚至數月,最後才嘗試將所有人的程式碼合併在一起。這種做法會導致:
- 合併地獄(merge hell):大量程式碼衝突需要解決
- 發現問題的時間延遲:整合問題直到合併時才浮現
- 風險集中:所有風險集中在合併階段
- 除錯困難:當出問題時,需要在大量變更中尋找原因
小批量整合的優勢#
頻繁的小批量整合帶來完全不同的體驗:
- 衝突最小化:每次只整合少量變更,衝突容易解決
- 快速回饋:問題在引入後幾分鐘內就被發現
- 風險分散:風險均勻分佈在每次提交中
- 除錯簡單:問題範圍限縮在最近的少量變更中
持續整合要求開發者至少每天將程式碼整合到主幹。分支的存活時間越長,合併的難度越高,風險越大。
基於主幹的開發(Trunk-Based Development)#
基於主幹的開發是實踐持續整合的基礎。其核心原則包括:
- 所有開發者都在主幹(trunk/main)上工作,或使用存活時間極短的分支
- 分支的壽命不超過一天
- 禁止長期存在的 feature branch
- 程式碼在合併前必須通過所有自動化測試
如果你的團隊有存活超過一天的分支,那就不是在真正地實踐持續整合。
持續整合的前提條件#
要成功實踐 CI,團隊需要具備以下條件:
- 全面的自動化測試套件:確保每次提交都能被快速驗證
- 所有內容在版本控制中:程式碼、設定、測試、環境定義
- 維持建構綠燈的紀律:當建構失敗時,修復它是最高優先事項
- 短小的提交:每次提交的變更量要小,便於審查和除錯
- 共同所有權:任何人都可以修改任何程式碼
持續整合的實踐#
保持建構快速#
建構時間直接影響回饋速度和開發者的生產力:
- 目標:建構和測試在幾分鐘內完成(理想情況下 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 伺服器應使用與生產環境相同的作業系統和設定
- 依賴的服務版本應該一致
- 環境差異是許多「在我的機器上可以運行」問題的根源
結論#
持續整合是實現快速流動的基礎實踐。透過要求開發者每天將程式碼整合到主幹、維持快速且可靠的自動化建構、以及在建構失敗時立即修復,我們確保了程式碼始終處於可部署狀態。這為後續的持續交付和持續部署奠定了堅實的基礎,使團隊能夠安全且頻繁地向客戶交付價值。