「博學而精熟,訓練有素,言談得體;此乃好運。」——佛陀(釋迦牟尼)

對 bug 的正確回應原本應該很簡單,作者稱之為 FFF

  • 找出它們(Find ’em)
  • 釐清它們(Figure ’em)
  • 修好它們(Fix ’em)

專案初期我們能做到 FFF,但隨著 bug 如潮水般湧來,好運耗盡、時間不足,正確回應就做不到了。

是壞運氣,還是壞管理?#

作者在 IBM 研究過十二個失敗的百萬美元專案,發現它們都因「壞運氣」而失敗——火災、水災、地震、流感讓半數人無法工作。但一位審稿人問:「你的對照組呢?」

他們回頭找了十二個成功的可比專案,赫然發現這些專案也都遭遇「壞運氣」,卻沒因此失敗:軟體被毀就還原備份、半數人請病假就靠結對編程與技術審查提供的冗餘知識撐住關鍵路徑。

結論:殺死前十二個專案的不是壞運氣,而是壞管理

由此,作者多了一個辨認管理不善專案的方法:專案經理總是把失敗歸咎於「壞運氣」

專案為何在尾聲手忙腳亂?#

作者參與過汽車嵌入式系統、遊戲、太空船控制、心律調節器、作業系統等各類軟體專案,從未找到所謂「軟體的本質」——唯一能區分成敗的因素,是管理品質

當作者看到一個專案在尾聲不慌不亂,就知道它管理得好。可惜很少人見過管理良好的軟體專案,甚至不信這種事存在,只說「軟體專案尾聲總是手忙腳亂,這就是軟體的本質」。

雖然沒有「軟體的本質」,卻有「某些管理不善專案的本質」,導致它們在尾聲爆炸的典型序列如下:

  1. 管理者不懂測試、釘定與除錯的差別
  2. 因為不懂,他們相信測試造成了專案大部分的麻煩
  3. 因為相信測試惹麻煩,他們傾向盡量拖延所有形式的測試
  4. 因為流程被設計成拖延測試,測試成了他們再也無法假裝一切順利的第一刻(管理更差者,因資訊免疫,甚至測了之後還能繼續假裝順利)
  5. 因為資訊免疫,早期階段一切看似「順暢」
  6. 因為管理者拖延,許多自需求階段就潛伏的 bug 在後期測試才現形
  7. 因為整個系統現在被混在一起,許多 bug 難以釘定——開發者此刻像無頭蒼蠅應付突如其來的 bug 洪流,幫不上忙
  8. 因為開發者在期限壓力下修舊錯製新錯,脾氣爆發、心智麻木、缺勤上升、會議暴增、策略反噬
  9. 於是參與者下結論:「開始測試前我們都沒問題、進度正常。是測試搞砸了一切。」

帶著這個結論,管理者開始規劃下一個專案——下一場恐慌的災難。

因此,對 bug 最首要的回應應該是預期它們。你不會走運,所以從專案一開始就把對的事做對:盡全力預防 bug,再對少數漏網的執行 FFF。

接近尾聲時該如何回應?#

但若你從一開始就沒做對的事呢?很遺憾,一旦專案陷入 bug 壓頂的恐慌,能用的好回應就所剩無幾了。

即使是管理最好的專案,接近出貨日時幾乎也必然殘留一些 bug。因此,第一個回應應該是為終局(endgame)排出時間

終局的步驟應該像這樣,而非計畫裡只擺一塊籠統的「測試」:

  1. 停止所有測試,開始規劃終局
  2. 依重要性為已知的殘留失敗排序
  3. 估計剩餘時間內,組織能可靠修好其中幾個(從最重要到最不重要)
  4. 把修不完的功能從出貨計畫中拿掉;若這會讓產品變得無法接受,就取消並重排出貨
  5. 依步驟 2 的重要性順序逐一移除 bug

當你決定要出貨、卻沒時間修新發現的 bug 時,停止「為了修而找 bug」是合理的(若有資源,可繼續找 bug 報告給客服,但要克制「匆忙修好」的衝動)。把修復人力重新分配,集中清掉已知的重要 bug,並用測試人員協助開發者釘定底層錯誤,再管理測試以揭露「修復本身」帶來的新 bug。

為何測試時間的估計與現實差這麼遠?#

專案開頭的估計不準,是尾聲手忙腳亂的另一原因。常見的估計錯誤有:

晴天估計(Sunny-day estimating)#

假設一切照計畫、沒有 bug 要修的估計。多麼愚蠢又危險的概念!如果真的不會有 bug,何必排測試?直接寫完出貨就好。

數學正確性證明先驅米爾斯(Harlan D. Mills)等人曾以為能完美地建造系統、讓測試變得不必要,但數十年來無人能為真實應用寫出完美程式,而且隨系統越複雜,難度越高。

不切實際的流程模型#

就像看鄰居蓋房子——當你開車經過覺得「外觀都好了」,卻納悶為何還要拖那麼久才完工。若你估計蓋房時間卻漏掉那些「看不見的」收尾工作,估計自然不準。

許多軟體估計出錯,正是因為漏掉了「收尾」步驟:釘定 bug、修復、重測、再修修復產生的新 bug。它們只在尾端擺一塊不加區分的「測試」時間,等同於蓋房計畫只寫「打地基、砌牆、上屋頂,然後收尾」——而「收尾」掩蓋了至少一半的工時。

流程資料品質差#

即使「收尾」被細分為「測試—釘定—修復—重測」循環,只要輸入資料稍有不準,估計仍可能大錯。作者示範某測試經理如何推導出八週估計:

  • 400 個測試案例,過往每 5 個案例找到 1 個 bug → 估 80 個 bug
  • 過往 2/5 的 bug 嚴重到需修 → 32 個
  • 剩餘 bug 約 1/2 需修 → 再 24 個,共 56 個
  • 過往每週能找修約 20 個 bug → 約 3 週處理 56 個
  • 1/4 的修復會帶 bug(14 個)需再循環 → 多一週,仍剩 4 個新 bug → 再一週清掉
  • 加一週修復、一週分級、一週讓測試啟動並累積 bug 待辦

合計八週(從實際開始把 bug 報告餵給開發者算起是五週),而非粗心經理估的三週。作者本人還會再加「測試排程的 25%」以容納生病、軟硬體阻塞、最後一刻變更等意外,使「測試」這塊總計十週。

關鍵變數是錯誤回饋比(fault-feedback-ratio, FFR)——修復中實際又餵進一個新 bug 的百分比:

  • 上例假設 FFR 為 25%(每修 4 個帶 1 個新 bug),但作者經驗中這算低
  • 許多組織的 FFR 若能低到 50%(每修 2 個帶 1 個)就要偷笑了
  • 把 FFR 從 1/4 改成 1/2,「測試」時間就從十週拉長到十五週
  • 作者甚至見過高達 4/5 的 FFR。切記:在壓力下修復會推高 FFR,所以想加快修復速度,往往反而拉高 FFR

沒有流程資料#

更糟的是,許多測試估計根本不基於資料,只是基於外部期望的「願望」,且不調整範圍或流程去遷就現實。典型對話:「24 週後絕對要上線……需求 4 週、架構 4 週、設計 4 週、編碼 8 週,加上人事兩週共 22 週,所以剩 2 週測試。」當設計延一週,就開大會說「砍測試一週就好,反正開發者很厲害、bug 不多」。

判斷你是否已過了能改變結果的時點#

對測試資訊最重要的回應,或許是判斷「任何回應是否還能改善軟體本身」。為此你可能得多等一會兒以取得更多資訊——等待是可接受的回應,只要你說清楚為何等待。

  • 絕不要宣稱你「只是在等」,永遠要指明一個特定事件或時間(或兩者)
  • 記住你的回應不只是話語:人們會聽你的語氣、看你的肢體語言,這些都影響士氣,所以保持開放、清晰、誠實

若你再也不能等、也沒時間取得更多資訊,仍有許多替代回應:照原樣出貨、把失敗當成特色、警告客戶、撤下部分功能、撤下整個產品,或從「事情開始出錯的那一點」(明顯不同於「你注意到出錯的那一點」)重來。

最激烈的回應是宣告專案破產、從頭來過。這可能讓你丟掉工作,卻能救你一命。無論是否丟工作,你都能帶著從這個專案學到的一切去做下一個——學費你已經付了,學不學是選擇題。

小結#

如果專案在測試之前就管理不善,大部分的好回應都將不再可用。許多情況下,沒有任何回應能拯救專案——除了重來,並從一開始就把它做對。

常見錯誤#

以下是回應 bug 時最常見的失誤。

  1. 依賴運氣:運氣眷顧管理良好的專案
  2. 削減測試時間與資源以趕上排程:若你不在乎品質,任何排程都能達成,那又何必測試?
  3. 測試提供產品真實狀態的資訊後,仍不調整排程與估計:沒人能準到對未來做絕對承諾,能對未來做承諾的人必是某種魔鬼
  4. 不蒐集流程資料:錯誤是「被製造」的,不是天生的。你越了解它們在何時何地被製造,就越容易偵測、釘定、定位、修復,或在下次預防
  5. 不懂測試何時開始:測試始於專案構思之時,甚至更早。不懂這點,就完全不懂測試
  6. 鞭打一匹死馬:若某個建置版本已殘廢、需要大量修復,別盲目繼續測試與回報 bug——大規模的修復會讓你的 bug 報告變得毫無意義