Bob Martin 以 CTO 的身分,對品質提出一系列期望。核心訊息是:品質不是 QA 的責任,而是開發者的責任。從持續改善到測試自動化,每一條標準都指向同一個方向——開發團隊必須對品質負起完全的責任。
Continuous Improvement(持續改善)#
人類讓事物隨時間變好:電腦、汽車、飛機、道路、電話、醫療技術、太空科技、整個文明——全都比以前好。那為什麼軟體會隨時間退化?
CTO 的期望:
- 系統的設計和架構應隨時間改善
- 軟體應該每過一週就變得更乾淨、更有彈性
- 變更的成本應該隨軟體壽命下降而非上升
- 每次 programmer check in 程式碼時,都應該比 check out 時更乾淨
- 不管你碰程式碼的原因是什麼——修 bug、加功能——都應該同時讓程式碼變更好
讓軟體隨時間改善需要的不是什麼神奇技術,而是意志(will)、態度(attitude)、以及對紀律的承諾(commitment to the disciplines)。
Fearless Competence(無畏的專業能力)#
恐懼如何蠶食能力#
當系統的內部結構退化,複雜度會快速變得難以駕馭。開發者自然會越來越怕做改動——即使是簡單的改善也充滿風險。這不是程式設計師變笨了,而是系統的複雜度超越了程式設計師的自然處理能力。
恐懼帶來的惡性循環:
- 害怕改動 → 只做「最安全」的改動
- 「最安全」的改動往往不是改善系統的改動,反而讓系統更加退化
- 估算越來越大、缺陷率上升、deadline 越來越難達成、生產力暴跌、士氣掉入谷底
解法:消除恐懼#
- 運用紀律建立開發者用生命信任的測試套件
- 搭配重構和簡單設計的技能
- 開發者就有信心和能力快速修復退化,保持軟體在持續改善的軌道上
CTO 期望團隊始終展現無畏的專業能力——不是魯莽,而是有測試作為後盾的自信。
flowchart TD
subgraph 惡性循環
A1["系統退化"] --> A2["恐懼"]
A2 --> A3["保守改動"]
A3 --> A4["進一步退化"]
A4 --> A1
end
subgraph 良性循環
B1["測試套件"] --> B2["信心"]
B2 --> B3["大膽清理"]
B3 --> B4["系統改善"]
B4 --> B5["更多信心"]
B5 --> B1
endExtreme Quality(極致品質)#
我們什麼時候開始接受「bug 是軟體的自然現象」的?什麼時候「帶著一定程度的缺陷出貨」變成可接受的了?什麼時候 beta 測試變成了大規模公開發佈?
Bob 的立場:
| 立場 | 說明 |
|---|---|
| 不接受 | bug 是不可避免的 |
| 不接受 | 預期會有缺陷的態度 |
| 期望 | 每個 programmer 交付的軟體在行為和結構上都沒有缺陷 |
| 認為 | 這個目標是否百分之百可達成並不重要——重要的是每個人接受它作為標準,並持續朝它努力 |
We Will Not Dump on QA(我們不把問題丟給 QA)#
QA 存在的悲哀原因#
為什麼公司要投資一整個獨立的部門來檢查程式設計師的工作?答案很簡單也很令人沮喪:因為程式設計師沒有做好自己的工作。
很多組織裡,QA 坐在流程的最末端,等著開發者把軟體「丟給」他們。開發者總是不能準時交付,結果是 QA 被迫壓縮測試時間來趕上發布日期——高壓、乏味、必須走捷徑。這顯然不是確保品質的方式。
The QA Disease(QA 病)#
一個根本的問題:你怎麼判斷 QA 做得好不好?靠他們發現多少缺陷嗎?
- 如果是,那 QA 會把缺陷視為正面的事——越多越好
- 開發者那邊也有類似的邏輯:「反正 QA 會找到 bug,那我先準時交付就好」
- 不需要任何口頭約定或握手——每個人都心照不宣地知道,有一個 bug 經濟在開發者和 QA 之間流動
- 這是一種非常深層的病態
sequenceDiagram
participant Dev as 開發者
participant QA as QA
participant Mgmt as 管理層
Dev->>QA: 交付含 bug 的軟體
QA->>Mgmt: 報告發現 N 個 bug(績效)
QA->>Dev: 回報 bug 列表
Dev->>QA: 修復 bug 但不改根因
Note over Dev,QA: bug 經濟循環:<br/>QA 需要 bug 來證明價值,<br/>開發者依賴 QA 找 bugQA Will Find Nothing(QA 應該什麼都找不到)#
如果 QA 被放在流程的末端,那 QA 應該什麼都找不到。開發團隊的目標應該是:末端的 QA 永遠找不到 bug。每次 QA 找到 bug,開發者都應該去調查原因、修正流程、確保不再發生。
QA 不應該在流程的末端——QA 應該在流程的開頭。QA 的工作不是找出所有 bug(那是程式設計師的工作),而是以足夠詳細的測試規格來定義系統行為,使得缺陷被排除在最終系統之外。這些測試應該由程式設計師來執行,而不是 QA。
flowchart LR
subgraph 錯誤流程
direction LR
X1["開發"] --> X2["交付"]
X2 --> X3["QA 找 bug"]
X3 --> X4["修復"]
X4 --> X5["再交付"]
end
subgraph 正確流程
direction LR
Y1["QA 定義測試規格"] --> Y2["開發(含自動化測試)"]
Y2 --> Y3["交付"]
Y3 --> Y4["QA 找不到 bug"]
endTest Automation(測試自動化)#
手動測試的代價#
在大多數情況下,手動測試是巨大的金錢和時間浪費。幾乎所有能自動化的測試都應該被自動化,包括:
- Unit tests
- Acceptance tests
- Integration tests
- System tests
手動測試應保留給需要人類判斷力的場景:
- 檢查 GUI 的美學
- Exploratory testing(探索性測試)
- 主觀評估互動的易用性
Exploratory Testing#
探索性測試值得特別提及。這種測試完全依賴人類的創造力、直覺和洞察力。目標是透過大量觀察系統行為來經驗性地推導系統行為,推斷邊界案例並設計路徑來測試它們。這需要相當的專業能力。
開發者的責任#
- 大多數測試都是簡單的 Arrange/Act/Assert 結構,提供固定輸入、檢查預期輸出
- 開發者有責任提供可透過函式呼叫的 API,讓測試能快速執行且不需要複雜的環境設置
- 開發者應抽象化任何緩慢或高設置成本的操作(例如 RDBMS),讓測試能用固定資料替代,大幅提升測試的速度和可靠性
- 緩慢的周邊設備、介面和框架也應被抽象化,讓個別測試能在微秒內執行、與任何環境隔離、不受 socket timing、資料庫內容或框架行為的影響
Automated Testing and User Interfaces(自動化測試與使用者介面)#
自動化測試不應該透過使用者介面來測試業務規則。UI 會因為時尚、便利性和行銷需求而頻繁變動,這些原因與業務規則無關。當自動化測試透過 UI 驅動時,測試會變得非常脆弱,最終往往因為太難維護而被丟棄。

Figure 10.1: Tests driven through the user interface
正確做法:透過 API 測試#
開發者應用函式呼叫 API 將業務規則與使用者介面隔離。透過這個 API 的測試完全獨立於 UI,不受介面變更的影響。

Figure 10.2: Tests through the API
Testing the User Interface(測試使用者介面)#
如果業務規則已透過函式呼叫 API 進行自動化測試,那麼 UI 本身需要的行為測試就大幅減少了。測試 UI 時應注意:
- 用 stub 替換業務規則,提供固定值給 UI
- 這確保 UI 測試的快速和明確

Figure 10.3: The stub supplies canned values to the user interface
根據 UI 的複雜度選擇策略#
- 大型複雜 UI:可使用自動化 UI 測試框架,搭配 business rule stub 讓測試更可靠
- 小型簡單 UI:手動測試可能更實際,特別是需要評估美學的情況;同樣搭配 stub 讓手動測試更容易進行
CTO 的期望:所有實際上可以自動化的測試都應該被自動化,測試應該執行得快,而且測試不應該是脆弱的。