iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
Software Development

AI時代下的軟體工程系列 第 11 篇

Day11: CI:更新共用版本前的最後一道關卡

  • 分享至 

  • xImage
  •  

What is CI

CI 這個詞對多數開發者並不陌生,而且它很少單獨出現,通常和 CD 一起被介紹,合稱 CI/CD。要理解兩者的分工,可以先把它們放回 DevOps 的整體流程來看:

圖片:DevOps processes 循環圖,依序為 Dev、Build、Test、Release、Deploy、Operate、Monitor & Analyze,再經由 Design 回到 Dev;兩側分別說明各階段的工作,例如 Build 為建立可執行的產物、Test 為盡可能自動化測試、Release 為核准部署、Deploy 為移至 production 環境

圖片來源:CMU 17-636 DevOps, Lecture 1: Introduction

DevOps 把軟體從開發到上線、再回到開發的過程視為一個循環。CI 與 CD 分別負責這個循環中的不同區段:

  • CI(Continuous Integration,持續整合):對應 Dev → Build → Test。定期將程式碼的修改建置、測試,並合併回主分支。
  • CD(Continuous Deployment,持續部署):對應 Release → Deploy。自動測試並將 repo 中的修改發布到 production 環境。

兩者雖然常被並列,普及程度卻不相同。Brown 大學 CSCI 2952-F 的課程投影片中提到,CI 幾乎是所有軟體專案的標準配備,CD 則不然,例如航太、醫療等產業並不適合讓修改自動上線。原因在於,不是每個專案都需要部署,但只要專案會持續更新,每一次把修改合回共用版本,都是一次 integration。

在這篇文章裡,我們會把 CI 理解為一道專案層級的 quality gate(品質關卡)。remote 上的主分支是團隊共用的 source of truth,CI 就位在更新這個版本之前的最後一關:程式碼必須先通過檢查,才能被合併進去。至於要檢查什麼,前幾天介紹的 formatter、linter、type checker 與 test 都是常見的項目,實際的組合則由各個 repo 自行定義。

Why we need CI

Quality gate:讓檢查成為專案的規則

前面介紹的每一種工具,都能在開發者自己的電腦上執行。但只要檢查是在個人環境中進行,它就取決於個人的習慣與設定:有人會記得在提交前跑一次測試,有人不會;即使大家都有執行,本機上的工具版本也未必一致。隨著參與的人數與修改的頻率增加,「每個人都記得檢查」就不再是可靠的假設。

CI 把檢查從個人的習慣,轉變為專案層級的規則:

  • 每次變更都會觸發:push 或開 pull request(PR)時自動執行,不依賴任何人記得。
  • 在統一的環境執行:每次都在乾淨的機器上安裝指定版本的工具,結果不受個人環境影響。
  • 可以設為合併的必要條件:未通過檢查的 PR 無法合併。

換句話說,CI 保證的是:任何進入主分支的程式碼,都經過了同一組檢查。

Local quality gate:pre-commit hook

CI 解決了一致性的問題,但它有一個明顯的代價:回饋來得太晚。

若所有檢查都只在 remote 執行,每次都要 push、等 CI 跑完才知道結果,一個格式錯誤就得來回好幾趟,而這些問題本來在自己的電腦上幾秒內就能解決。

因此,實務上會把一部分檢查提前到本機,在修改離開開發者的電腦之前先攔下來,也就是 local quality gate。最常見的做法是 Git 的 pre-commit hook:Git 會在建立 commit 之前執行它,若檢查失敗,這次 commit 就會被中止。

需要注意的是,local quality gate 無法取代 CI。pre-commit hook 需要每個人自行安裝,也可以用 git commit --no-verify 直接跳過。它的定位是讓問題更早被發現,而確保問題不會進入主分支,仍然是 CI 的工作。

兩道關卡的分工

https://ithelp.ithome.com.tw/upload/images/20260924/20128319YviU2OnZok.png

既然兩道關卡的定位不同,放在上面的檢查也應該有所區分:

pre-commit hook(local) CI(remote)
觸發時機 每次 commit push、PR
速度要求 數秒內 可以到數分鐘
檢查範圍 本次修改的檔案 整個 repo
適合的檢查 formatter、linter;type checker 與 test 只跑與本次修改相關、能快速完成的部分 四種檢查全部完整執行,必要時涵蓋多個版本/平台
能否繞過 可以(--no-verify) 設為必要條件後不行

pre-commit hook 一旦執行太久,開發者很快就會習慣性地跳過它,所以只能跑部分檢查;而只檢查修改到的檔案,可能漏掉跨檔案的問題,完整的檢查仍要交給 CI。

簡單來說,local gate 負責快速回饋,remote gate 負責不可繞過。

常見的設定

CI

各個 CI 平台的語法不同,但設定的內容大致相同:

  • 觸發條件:push 到特定分支、開啟或更新 PR、定時排程。
  • 執行環境:作業系統與語言版本,也可以同時在多個版本上各跑一次。
  • 執行步驟:安裝依賴,再依序執行各項檢查。formatter 在這裡以 check 模式執行,CI 只判斷能否通過,不替開發者修改。
  • 合併條件:哪些檢查必須通過才能合併,通常在託管平台上設定,例如 GitHub 的 branch protection。
平台 設定檔位置
GitHub Actions .github/workflows/*.yml
GitLab CI/CD .gitlab-ci.yml

設定檔和程式碼放在同一個 repo 裡,修改檢查規則,和修改程式碼一樣需要經過 review。

pre-commit hook

Git 的 hook 預設存放在 .git/hooks/,這個目錄不受版本控制。因此團隊通常會使用 hook 管理工具,把設定寫成檔案納入版控,每位開發者在本機啟用一次即可。設定的內容包括:

  • 要執行的檢查:以及各個工具固定使用的版本。
  • 檢查範圍:只檢查特定類型的檔案,或排除自動產生的程式碼。
  • 觸發時機:除了 commit 之前,也可以掛在 push 之前,或用來檢查 commit message。

最常用的工具是 pre-commit,設定寫在 .pre-commit-config.yaml;Git 本身支援的所有 hook 類型,可以參考 Git 官方文件。

CI 如何幫助 AI

Remote quality gate:守住工具能檢查的部分

AI 讓程式碼產生的速度大幅提升,review 的負擔也跟著變重。有 CI 把關工具能檢查的部分,reviewer 就能專注在工具無法判斷的地方:需求是否被正確理解、設計是否合理。不過,CI 通過只代表修改符合 repo 所定義的檢查;檢查該如何定義,仍然需要由人負責。

Local quality gate:coding agent 最主要的回饋來源

對 coding agent 而言,local gate 比 remote gate 更關鍵。agent 的工作方式本身就是一個迴圈:修改程式、執行檢查、讀取結果、再修改。local 檢查的結果在幾秒內就能回到這個迴圈,此時相關的修改還在 agent 的 context 裡,可以當下修正;CI 則要等到 push 之後,錯誤才會以 log 的形式回來,agent 還得回頭推敲是哪一次修改造成的。

四種檢查在 local 都能提供回饋,但對 agent 的價值並不相同:

檢查 在 local 對 agent 的幫助
formatter 自動修正格式,agent 幾乎不需要處理
linter 指出有固定形狀的陷阱,修正方式通常很直接
type checker agent 常只讀了部分檔案,修改介面後容易漏掉其他呼叫端;型別檢查能直接指出哪裡的假設不一致
test 唯一檢查行為是否符合預期的工具;失敗訊息指出哪個 case、預期與實際輸出各是什麼,讓 agent 有明確的修正方向

formatter 與 linter 處理的是寫法,type checker 與 test 處理的則是程式對不對,這也正是 agent 最容易出錯、卻不容易自己察覺的地方。人會因為等待而跳過較慢的檢查,agent 不會;因此在 agent 的工作流程中,值得要求它在 commit 前就執行 type check 與相關的 test,而不是把這些錯誤留給 CI 才發現。

修改程式 → local 檢查(format、lint、type check、test)→ 依回饋修正 → push → CI 完整檢查 → 合併

local gate 讓 agent 在自己的迴圈裡把大部分問題修掉,CI 則確保最終進入主分支的程式碼,都通過了專案定義的完整檢查。

Reference


上一篇
Day10: Test:把預期行為寫成可執行的例子
下一篇
Day12: Docs:只留下需要,而且仍然有效的文件
系列文
AI時代下的軟體工程 共 12 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言