iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
Claude AI

用 AI Agent 重構一套無框架的 legacy PHP 系統系列 第 6

Day 06:與乾淨基準比對——把「本機環境雜訊」跟「真的迴歸」分開

  • 分享至 

  • xImage
  •  

前言:測試變紅了,是我改壞的,還是本來就這樣?

「跑測試,紅字,代表這次改動有問題」——這句話聽起來理所當然,但在一套運作多年、缺乏完整測試網的系統上,這個推論其實有一個沒說出口的前提:你要先確定,這些紅字在你改動之前就不存在

前五天講的是動手前的準備:確認分支基準、用覆蓋率門檻決定哪些程式碼真的敢改、驗證 PHP 版本相容性。這些都是「動手前」要做的事。從今天開始,我們正式進入這個系列的第二部——讓 AI 安全動手的核心機制。而第一個要處理的問題,發生在「動手之後」:改完之後測試紅了,這代表迴歸嗎?

答案沒有那麼直覺。我接手的這套系統歷史夠長、環境夠複雜,本機驗證環境本身就會產生雜訊——殘留的測試資料、PHP 版本落差造成的套件行為差異、甚至單純只是某個測試本來就不穩定(flaky)。如果 AI 看到紅字就直接判定「是我這次改動造成的」,然後開始「修」,很可能是在修一個根本不存在的問題,還可能把本來沒事的地方越改越糟。

今日目標

  • 理解「帶著改動跑測試」這個動作本身無法回答「這是不是我造成的」
  • 學會用「乾淨基準比對」把改動的影響跟環境雜訊分開
  • 理解為什麼這個比對過程要放在獨立流程裡跑,而不是主線程直接做
  • 建立「AI 只負責產生差集報告,不自行判斷能不能忽略」這條邊界
  • 看一個因為沒做這道比對、AI 差點誤判方向的具體案例

一次測試結果,回答不了「是不是我改壞的」

假設你請 AI 對一段 legacy 程式碼做了收斂——把幾十處手寫 SQL 改成透過 Repository 呼叫。改完之後跑一次全套測試,出現了 12 個失敗。

這 12 個失敗代表什麼?可能性至少有三種:

  1. 這次改動真的引入了迴歸,行為跟原本不一致
  2. 這 12 個測試本來就會失敗,跟這次改動完全無關(環境雜訊、殘留資料、版本落差)
  3. 其中一部分是真迴歸、一部分是雜訊,混在同一份紅字清單裡

只跑一次測試,永遠回答不了「這 12 個各自屬於哪一種」。你需要一個對照組。

具體做法:帶改動跑一次,拿掉改動再跑一次

實務上的做法很直接:

  1. 帶著改動跑一次全套測試,記錄失敗的測試名稱清單(不是失敗數量,是完整名稱清單)
  2. git stash 把改動暫存起來,讓工作目錄回到改動前的乾淨狀態
  3. 再跑一次同一套測試,一樣記錄失敗的測試名稱清單,這就是「乾淨基準」
  4. 取兩份清單的差集——只留下「帶改動時失敗、乾淨基準沒失敗」的測試,這才是真正因為這次改動新增的紅字
  5. 跑完立刻 git stash pop 把改動還原回來

差集是空的,代表這次改動沒有引入任何新迴歸,那 12 個失敗全部是環境本來就有的雜訊,可以放心繼續往下走。差集不是空的,才代表真的有東西要處理——而且處理範圍精準縮小到差集裡列出的那幾個測試,不用大海撈針。

用一組對照看差異:

❌ 沒有比對基準的版本:
AI:「跑完測試,12 個失敗,這次改動看起來有迴歸,我來修一下。」
→ 直接假設全部 12 個都是這次改動造成的
→ 可能把跟改動無關的舊有失敗也「修」了一遍,
   引入新的、跟原始需求無關的變更

✅ 有乾淨基準比對的版本:
AI:「帶改動跑測試:12 個失敗。
     git stash 後跑乾淨基準:11 個失敗(同一批舊有失敗一直都在)。
     差集:1 個新增失敗,是 XxxTest::yyy_test。
     這是這次改動唯一造成的迴歸,其餘 11 個跟這次改動無關。」
→ 精準定位真正需要處理的範圍,不擴大戰場

這兩個版本的差別不是 AI 細不細心,是有沒有一個對照組。沒有乾淨基準,AI 對「測試紅了」這件事的判斷,跟丟硬幣猜差不多。

為什麼要在獨立流程裡跑,不要主線程直接做

這道比對聽起來簡單,但實際跑起來有兩個實務上的理由,不適合放在主線程直接做:

第一,全套測試通常要跑好幾分鐘,帶改動跑一次、乾淨基準再跑一次,等於要等兩倍時間。如果這個過程佔用主對話的上下文,會讓後續每一輪互動都要背著這兩次測試的完整輸出(動輒上千行的測試框架輸出),拖慢整個對話,也讓真正該關注的訊息被稀釋掉。

第二,也是更重要的一點:這個過程本身容易產生誤判的誘惑。如果 AI 一邊跑測試一邊在同一個上下文裡「順手」判斷「這幾個失敗應該是無關的吧」,很容易變成沒有真的做完整比對、單憑印象就下結論。把這個流程獨立出去,逼自己完整跑完兩次、產生一份確實的差集報告,再回到主線程根據這份報告討論怎麼處理,能有效避免「跑到一半就開始腦補結論」的捷徑心態。

回報格式也要固定下來:差集是空的,要明講「沒有新增迴歸」,不能只說「看起來沒問題」;差集不是空的,要列出完整測試名稱,不能用「有幾個失敗跟這次改動有關」這種摘要帶過。

一條硬性規定:AI 不自己判斷能不能忽略

這道比對機制裡,還藏著一條更重要的邊界:AI 只負責跑出乾淨的差集報告,不負責判斷「這個差集裡的失敗能不能忽略」

這個界線的理由跟系列第一天講的那句話是同一件事——AI 給出的「已確認」結論,永遠只在它實際查過的範圍內成立。差集比對能確認「這個失敗是不是這次改動造成的」,但確認不了「這個失敗重不重要」「能不能先擱置」。這種帶著業務判斷、風險承受度考量的決定,不該讓 AI 自己拍板,得交回給人。

我曾經看過一個相反的例子:某次改動的差集裡出現了一個新增失敗,AI 判斷「這個測試斷言的是一個邊界情境,實務上流量很小,應該可以先不管」,就這樣把它晾在一邊繼續往下做。這個判斷聽起來合理,但「流量小」是對當下資料現況的觀察,不代表這個邊界情境在協定設計上就是不重要的——這正是「用觀察到的資料現況,取代協定本身正不正確」的思維捷徑,跟這個系列後面會講到的另一個案例(判斷分頁邏輯要不要做完整,卻用「目前流量沒觸發」當理由不修)是同一種錯誤的兩個面貌。差集報告只負責把問題找出來、精準定位,要不要處理、什麼時候處理,是人的決定。

今日思考題

回想你自己重構時的經驗:測試紅字出現的當下,你是先假設「是我剛剛改壞的」,還是先去確認「這些失敗改動前就存在嗎」?如果從來沒做過乾淨基準比對,下次不妨試著跑一次,看看真正屬於你這次改動的紅字有多少——很可能比你以為的少。

今日重點回顧

  • 一次測試結果無法回答「這是不是我造成的」,需要乾淨基準當對照組
  • 具體做法:帶改動跑一次、git stash 後跑一次乾淨基準、取差集,只有差集裡的才是真迴歸
  • 這個比對流程適合放在獨立流程裡跑,避免佔用主線程上下文、避免跑到一半就腦補結論
  • AI 只負責產生精準的差集報告,「能不能忽略」的判斷交回給人
  • 這條規則跟系列主題句是同一件事:AI 的確認範圍,要跟它實際查證的範圍一致,不能用「看起來沒問題」代替「真的比對過」

明日預告

明天要往下追問一層:為什麼這道比對、以及後面會提到的其他驗證流程,都建議放進獨立的 subagent 或子流程裡跑,而不是讓主線程一邊做一邊判斷?背後的理由不只是效能,還牽涉到「怎麼避免驗證過程本身污染判斷」這件事。


上一篇
Day 05:PHP 版本相容性驗證——本機新版 PHP vs 正式環境舊版 PHP 的陷阱
下一篇
Day 07:為什麼要在獨立 subagent/子流程裡跑驗證迴圈
系列文
用 AI Agent 重構一套無框架的 legacy PHP 系統8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言