《Clean Craftsmanship》Podcast 準備稿:TDD 三法則與「先寫測試」的哲學
書名: 整潔的軟體工藝 Clean Craftsmanship(Disciplines, Standards, and Ethics) 作者: Robert C. Martin(Uncle Bob) 系列: Reading Uncle Bob(恩普拉氏) 公開標題建議: Reading Uncle Bob|Clean Craftsmanship.TDD:軟體開發的複式簿記 (2/9) 涵蓋範圍: Part I 第2章 Test-Driven Development(三法則、紅綠重構、三個經典範例)
背景速覽
這集是整本書的心臟。TDD 是 Uncle Bob 口中的「基石紀律」——沒有它,重構不安全、簡單設計淪為空談。本章用一個很妙的歷史類比(複式簿記)為 TDD 定錨,然後丟出著名的「三法則」,最後用三個從零開始的範例(Stack、質因數分解、保齡球計分)展示 TDD 的節奏與威力。這集講好,後面七集都站得穩。
一句話重點
TDD 的三法則把你鎖進一個只有幾秒鐘長的循環——寫一行測試讓它失敗、寫剛好夠的產品碼讓它通過、再重構——而這個看似機械的紀律,真正的回報是「一個你願意以生命信賴的測試套件」,它讓你不再害怕改程式碼。
值得討論的重點
1. 複式簿記的類比:所有事情都被表述兩次
這是本章最漂亮的開場。複式簿記 1494 年由 Luca Pacioli 正式記錄,核心是「每筆交易都有兩面,所有借貸相加必須為零」。Uncle Bob 說:TDD 就是軟體開發的複式簿記——每個行為都被表述兩次,一次在測試裡、一次在產品碼裡,靠「保持測試通過」來維持平衡。任何一邊出錯,平衡就被打破,你立刻知道。這個類比好用在哪?它把 TDD 從「多寫一堆測試的苦差事」重新框成「一種對稱的、自我校驗的會計紀律」——會計師不會抱怨「為什麼要記兩次」,因為那正是不出錯的機制。
2. 三法則:為什麼是「秒級」而不是「分鐘級」
- 第一法則:在寫出「因缺少產品碼而失敗的測試」之前,不要寫任何產品碼。
- 第二法則:測試只寫到「剛好足以失敗」(含編譯失敗)就停。
- 第三法則:產品碼只寫到「剛好讓當前失敗的測試通過」就停,然後回去寫更多測試。
關鍵在於這三條把循環壓到秒而非分鐘。通常測試的第一行就會編譯失敗(引用了還不存在的東西),你幾乎寫不到一行就得切回去寫產品碼。很多人第一次聽會覺得「這也太極端、太慢了吧」——但 Uncle Bob 的回報清單很有說服力:告別除錯(一切都在一分鐘前還是綠的,你要除什麼錯?)、測試即文件(最底層、可執行、永不過期的使用範例)、補上設計漏洞(事後補測試會逃避難測的程式碼,先寫測試逃不掉)、以及最核心的——消除恐懼。
3. 紅綠重構,與三個範例的「演算法自己浮現」
Kent Beck 的箴言「先讓它能動,再讓它正確」催生了第三個顏色:紅 → 綠 → 重構。三個範例層層遞進:
- Stack:教基本節奏,還教一條反直覺的 Rule 3「Don’t go for the gold」——別急著測最有趣的核心功能(FILO),先處理外圍(空、大小、例外),常常在過程中就把核心簡化掉了。
- 質因數分解:本章最神的一段。Uncle Bob 本來打算寫埃拉托斯特尼篩法,結果「先寫測試看看」,演算法竟然一個測試一個測試地自己浮現,最後只剩三行核心碼,他還得回頭「研究」自己寫出來的東西才懂它為何有效。金句:「隨著測試越來越具體,程式碼越來越一般化。」
- 保齡球計分:物件導向直覺會畫出 Game/Frame/Roll 的 UML、約 400 行、四個類別、可以分給四個人寫。TDD 導出的版本只有 14 行,一個 for 加兩個 if,連「第十格特例」都消失了——測「完美比賽 300 分」時預期會失敗,結果直接通過。Uncle Bob 的反問很爽:「你寧願維護四個類別 400 行,還是 14 行?」
注意事項
⚠️ TDD 是整季最容易被當成教條的一塊,務必平衡。 這裡一定要請出 DHH(David Heinemeier Hansson)2014 年的〈TDD is Dead〉與隨後 DHH/Kent Beck/Martin Fowler 的三方對談。DHH 的核心批評不是「測試沒用」,而是「先寫測試、追求 100% 單元測試、為了可測性而扭曲設計,會傷害設計而非幫助設計」。Uncle Bob 是 TDD 最強的傳道者,立場鮮明;節目要誠實呈現對立面——TDD 是一套強力工具,但「任何時刻都嚴格遵守三法則」在真實世界裡是有人做、也有很多高手不做的。
⚠️ 三個範例都是「演算法 / 純函式」題材(堆疊、質因數、計分),TDD 在這類題目上幾乎是魔法。但別讓聽眾以為所有程式都這麼好測——UI、第三方整合、有大量副作用的膠水程式碼,TDD 的投報率會明顯下降(這正是 DHH 的痛點之一)。下一集的 Test Doubles 與不確定性原理會處理一部分,但要先打預防針。
⚠️ 保齡球那個「14 行 vs 400 行」很有戲劇性,但別過度推論成「TDD 永遠導出更簡單的設計」。它導出的是更貼合問題本質的設計——前提是你願意在過程中聽從 Rule 6(程式碼感覺不對時,先修設計再繼續)。沒有那份重構紀律,TDD 一樣會長出爛 code。
專家補充
💡 「測試即文件」這點,可以接到一個現代延伸:很多團隊用 TDD 寫出來的測試,其實就是最好的 onboarding 材料。新人想知道一個 API 怎麼用、邊界條件是什麼,看測試比看過期的 wiki 文件可靠一百倍——因為測試會被 CI 強制保持正確,文件不會。
💡 質因數那段「演算法自己浮現」呼應一個更大的命題:Uncle Bob 暗示 TDD 「或許是一種漸進式推導演算法的通用技術」。這話講大了(沒人能用 TDD 推導出 FFT 或 Dijkstra 最短路徑),但它指向一個真實的洞見——當你被迫從最退化的案例開始、每步只做最小的一般化,你常常會繞過自己的過度設計。這跟下一集要講的「轉換優先前提」是同一條思想線。
💡 給聽眾一個落地建議:不必一開始就嚴守三法則。可以先從「bug 修復一定先寫一個能重現它的失敗測試」開始——這是 TDD 投報率最高、爭議最小的入門點,連反對 TDD 的人通常也同意。
討論問題
🎙️ 開場鉤子:「有沒有一種寫法,能讓你打開任何一份程式碼時都確定它『一分鐘前還是好的』?如果有,你還需要會用除錯器嗎?」
🎙️ 自問自答:「先寫測試到底反不反直覺?」——用第一法則回答:如果你寫得出產品碼,你就寫得出測它的碼,只是順序對調;真正反直覺的不是「先寫」,是「忍住不要多寫」。
🎙️ 拋給聽眾的對立題:「Uncle Bob 說嚴守三法則,DHH 說 TDD is dead——你站哪邊?還是你其實兩邊都對一半?」
🎙️ 帶走的一題:「這禮拜修下一個 bug 時,先寫一個會失敗、能重現它的測試再動手。只要一次,感受一下那個『綠燈亮起』的踏實感。」
更大範圍關聯
- TDD 的源頭:Kent Beck《Test-Driven Development: By Example》(2002) 是 TDD 的開山之作,本章的紅綠重構、保齡球範例的精神都源自此。聽眾想真正學 TDD,那本才是教科書,這章是「為什麼」。
- 對立陣營:DHH〈TDD is Dead〉與 Martin Fowler「Is TDD Dead?」對談系列,是這集最該並陳的對照組。John Ousterhout《A Philosophy of Software Design》也對「為測試而拆小函式」有保留。
- 同系列接點:本章的「先讓它能動再讓它正確」「童子軍規則」直接呼應《Clean Code》EP1 講過的命名與童子軍規則——可以提醒老聽眾這是 Uncle Bob 一以貫之的核心習慣。
- 領域定位:用 [軟體工程領域切分藍圖] 看,TDD 同時是「測試」與「設計」兩塊的交集——這章最大的主張就是「測試其實是一種設計活動」,難測 = 耦合太緊。
錄製建議
- 建議時長:約 25-28 分鐘(本書最厚的一章,值得給足時間)。配比:複式簿記類比 4 分、三法則與好處 9 分、紅綠重構 3 分、三範例 9 分、TDD 爭議(DHH)4 分。
- 討論策略:用「一分鐘前還是綠的」開場最有共鳴;三範例不必逐行講程式碼(Podcast 講 code 很乾),改成講「故事與轉折」——質因數的「演算法自己浮現」、保齡球的「14 行打敗 400 行」都是天生的橋段。務必在後段花足 4 分鐘認真呈現 DHH 的反方,不要草草帶過——這是整季「帶腦讀經典」立場的試金石。