為什麼零 Bug 的程式碼是錯誤的目標

每一套系統都存在還沒有人踩到的缺陷,而當明顯的問題被清掉之後,找出下一個的成本會急遽上升。超過某個點之後,多花一小時去獵捕缺陷,價值會低於把同樣一小時拿來讓失敗更容易被發現、也更便宜地修好。

第二個問題出在文化。當零 Bug 被訂為目標,一個 Bug 就變成需要交代的過失,而不是可以拿來行動的資訊,於是大家對它愈來愈不出聲。

三個真正可行的目標

不重複發生

  • 同一個 Bug 只發生一次。每一次修復都留下一道檢查。

  • 做得到,而且會持續累積。

在使用者之前發現

  • 把發現問題的時機從正式環境往前移到 pull request。

  • 可量測:有多少比例是在內部就攔下來的。

修復成本低

  • 從失敗到修好所花的時間,而這主要取決於失敗報告的品質。

為什麼第一個最重要

一個從不讓同一個 Bug 出貨兩次的團隊,本質上每個月都會變得更好。這只需要一個習慣:修好東西的時候,留下一道檢查。多數團隊修掉 Bug、關掉票,卻沒有留下任何紀錄,說明這段行為曾經需要被保護。

該量測什麼

追蹤在發布前就被找到的缺陷佔比,以及從失敗到修好的時間。只有真的有東西變好,這兩個數字才會動,而且都沒辦法靠多寫測試來灌水,這正是它們有用的地方。測試數量和覆蓋率百分比要多少有多少,卻幾乎說明不了什麼。

為什麼團隊還是繼續追

知道這個目標是錯的,並不會讓人停止瞄準它;而背後的原因值得理解,因為它是結構性的,不是單純的天真。

Bug 看得見,預防看不見。一個流到客戶手上的缺陷會有一張票、一個名字和一個負責人。發布前被攔下來的那十二個什麼都沒有,因為什麼事都沒發生。於是一季下來看得到的紀錄就是一份失敗清單,而面對一份失敗清單,最自然的反應就是要求失敗少一點。

解法是讓預防也看得見。在回報有多少缺陷外流的同時,也一併回報有多少缺陷在發布前就被攔下來。前面那個數字通常大得多,看見它會讓討論從「我們為什麼一直有 Bug」轉向「這個比例有沒有在往好的方向走」,而後者才是有用答案的問題。

實際做起來是什麼樣子

每個 Bug 都配一道檢查。檢查在每一次變更時執行,而不是等到發布前才跑。失敗回報的形式,要讓負責修的人不必重新推敲來龍去脈就能動手。

終端機

npm install -g @testsprite/testsprite-cli
testsprite setup

如果不想在本機安裝,儀表板也涵蓋了同樣的範圍;完整的指令則收錄在 CLI 儲存庫。

觸發方式比機制更重要。把它接到你的部署事件上,代表每一次變更都會被檢查,不需要任何人特地決定要不要跑; GitHub App 可以從儀表板做到這件事,而 GitHub Actions 的步驟則是在你的工作流程裡做到。

TestSprite 如何支援這三個目標

「不重複發生」是它支援得最直接的一項。重現這個 Bug 的測試案例會留在專案裡,並在每一次變更時執行,所以修復本身就留下了一道檢查,不需要有人記得要去寫。

「在使用者之前發現」是節奏的問題。測試涵蓋範圍是從你的產品產生出來的,並在 pull request 上執行,這讓發現問題的時機從正式環境往前拉回到造成問題的那次變更。

「修復成本低」取決於失敗報告。一次執行回來的內容是:嘗試了什麼、應用程式實際做了什麼,以及兩者在哪裡分岔,所以負責修的人——愈來愈常是 coding agent——是從證據開始,而不是重新拼湊事情經過。

零 Bug 有可能做到嗎?

對於規模小、有形式化規格的系統,可以很接近,但代價高到幾乎沒有人划得來。對一般產品來說,不行。

合理的缺陷率是多少?

拿你自己的趨勢來比,而不是拿業界數字來比。方向比高低重要。

測試做得愈多,Bug 就愈少嗎?

到某個程度之前是。過了那個點,多加的測試只會增加維護成本,卻不會增加有用的訊號,尤其是當它們重複了你已經涵蓋的部分。

我們該追蹤 Bug 數量嗎?

追蹤外流的缺陷,以及修復所需的時間。原始數量會在回報品質變好時跟著上升,所以它是個很差的訊號。

最有槓桿效果的單一習慣是什麼?

每次修好東西,就留下一道檢查。這是唯一會持續累積的習慣。

簡短版

目標是不重複發生,而不是歸零。

零 Bug 的程式碼做不到,還會扭曲優先順序。把目標放在不重複發生、在使用者之前發現,以及修復成本低。每次修復後都留下一道檢查,並且量測外流的缺陷,而不是測試數量。