第 3 / 10 部 待錄

兩種風格初次對決

《Functional Design》Podcast 準備稿:兩種風格初次對決

書名: Functional Design(Principles, Patterns, and Practices) 作者: Robert C. Martin(Uncle Bob) 系列: Reading Uncle Bob(恩普拉氏) 公開標題建議: Reading Uncle Bob|Functional Design.同一題寫兩遍,差在哪 (3/10) 涵蓋範圍: 第二部導言 + 第6章 質因數分解 + 第7章 保齡球遊戲

背景速覽

第一部把 FP 的觀念講完了。第二部開始做一件很實在的事:把同一道練習題用 OO(Java)和 FP(Clojure)各寫一遍,看看到底差在哪——而且兩邊都用 TDD(測試驅動開發)一步步長出來。這集是對決的開場,挑了兩道難度最低的 kata:質因數分解和保齡球計分。Uncle Bob 刻意按難度遞增排,因為他要證明一件事:題目越簡單,兩種風格越像;越複雜,差異才越爆發。先看「幾乎打成平手」的兩局。

一句話重點

在「主要做計算」的小程式上,OO 和 FP 寫出來的東西讀起來、結構上不分軒輊——測試序列幾乎一模一樣,因為測試比語言更接近問題的本質;但即使在這麼小的題目裡,FP 已經悄悄展現出「更早走向遞迴」「更自然地把關注點分離」的傾向。

值得討論的重點

1. 測試是比語言更基礎的東西

質因數分解這題,Java 和 Clojure 從 1 到 9 的測試節奏完全相同——先測 1(空結果)、再測 2、3、4(第一次出現多因數)…… 兩種語言在每個數字上「卡關」的點一致。這是個深刻的觀察:測試比寫法更接近問題本身。你換語言、換典範,但「這個程式該有哪些行為」是不變的。這也是 TDD 的價值——它先逼你想清楚「要什麼」,再讓「怎麼做」自然浮現。

2. FP 更早被逼向遞迴

有趣的分歧點:在 Java 端,測到 4 時還只是線性的 if 判斷,要到測 8、9 才被逼出迴圈;但 Clojure 端,測到 4 就非用遞迴不可了。Uncle Bob 的結論是「遞迴在語意上比 while 更基本」。而且 Clojure 還走了一段彎路(U-turn):為了 4 選了「真遞迴」,被 9 的測試逼著改寫成「尾遞迴」——由此得出一條經驗法則:有得選的話,優先用尾遞迴。這段彎路本身就是 TDD「讓設計缺陷自己暴露」的活教材。

3. OO 的「方便」可能藏著違反 SRP 的耦合

保齡球這題更有看頭。Java 版有個 Game 類別,同時負責「收球(roll)」和「計分(score)」——很自然,但這是兩個職責耦在一起。Clojure 版沒有 Game 類別,而是拆成 to-frames(把擲球資料整成 frame)和 score(計分)兩段純函式。後者是個漂亮的關注點分離:to-frames 是純粹的資料轉換,跟「算幾分」完全脫鉤。Uncle Bob 的評語很中肯:Java 版較簡單但較耦合,Clojure 版的關注點分離讓它在彈性與重用上略勝——但兩者都才十幾行,差距還沒真正拉開。

注意事項

⚠️ 這集要管理聽眾期待。Uncle Bob 自己說質因數分解是「整場比較中最不分勝負的一章」。如果你開場就喊「FP 大勝 OO」,這集會打臉自己。正確的框架是:這是熱身賽,刻意選平手的局,好讓後面真正的差異有對照基準

⚠️ Clojure 有個危險誘惑:它提供太多「方便的小工具」,可以把資料快速喬成想要的形狀。保齡球那段 Uncle Bob 寫了個 (map #(take 1 %) ...) 的「半通不通」便利寫法,自己都看不下去重寫了。他的警告很值得轉述給聽眾:當小技巧開始繁殖、妨礙閱讀,就該重寫。這跟語言無關,是工程素養。

⚠️ 別在 TDD 的紅綠循環細節上耗太久。聽眾抓「測試先行、結構自然長出」這個精神即可,不需要逐個測試案例復述。

專家補充

💡 「測試是比語言更基礎的東西」這句話,其實打中了 TDD 最常被誤解的點。很多人以為 TDD 是「為了測試覆蓋率」,但 Uncle Bob 這裡展示的是更深的東西:測試是問題的規格說明。當 Java 和 Clojure 的測試序列一致時,等於證明了「問題的形狀」獨立於實作語言。這也是為什麼他敢說 TDD 的紀律「和語言無關」(第 13 集會正面論證)。

💡 保齡球這題在工程圈是有歷史的——它是 Uncle Bob 在《Clean Craftsmanship》裡的招牌 kata,也是 TDD 教學的經典。值得提的是,保齡球 kata 有個著名的「反例」:Ron Jeffries 曾用「設計優先」寫了一版又臭又長的物件設計,Uncle Bob 則用 TDD 寫出極簡版——這場「設計 vs TDD」的對照本身就是軟體史趣聞,可當花絮。

💡 「關注點分離」在 FP 裡常常是免費附贈的。因為純函式不能有副作用,你被迫把「轉換資料」和「使用資料」拆開——Clojure 版保齡球的 to-frames/score 分離不是工程師刻意設計的,是語言的純度推著它走的。這是 FP 一個低調的好處:好設計常常是純度的副產品

討論問題

🎙️ 開場鉤子:「要比較兩種程式風格,最公平的方法是什麼?把同一道題用兩種寫法各寫一遍,並排看。今天我們就來看 Uncle Bob 怎麼用 OO 和 FP 各解兩道經典 kata——結果可能跟你想的不一樣。」

🎙️ 自問自答:「為什麼 FP 這麼早就被逼著用遞迴,而 OO 還在用 if?」——因為在沒有賦值的世界裡,遞迴是唯一能『推進狀態』的工具。while 是有了變數之後的便利品,遞迴才是更底層的東西。

🎙️ 帶走的一題:「下次你寫一個類別,發現它同時在做兩件事(像 Game 又收球又計分)——停一下,問自己:這兩件事是不是該分成兩段純粹的轉換?就算用 OO,這個習慣也會讓你的設計更乾淨。」

更大範圍關聯

  • 本書第二部開場:這集是「比較分析」五章的前兩章(最不分勝負的兩局)。下一集起難度上升,FP 與 OO 的差異會顯著放大。
  • 與《Clean Craftsmanship》互文:保齡球 kata 的完整版在 Uncle Bob 自己的《Clean Craftsmanship》第 1 章——那是 Reading Uncle Bob 系列的第五本,這集等於跟前作隔空呼應。
  • TDD 的思想脈絡:「測試是問題規格」這個觀念接得上 Kent Beck 的 TDD 原典與《Growing Object-Oriented Software, Guided by Tests》(GOOS)——後者書名直接點出「測試引導設計成長」。
  • kata 文化:質因數、保齡球都是 coding kata 經典,源自 Dave Thomas(《Pragmatic Programmer》作者)推廣的「程式練習如同武術型」理念。用 [軟體工程領域切分藍圖] 看,這扣到「工藝/實踐」這一支。

錄製建議

  • 建議時長:約 20 分鐘。配比:第二部框架+為何比較約 4 分、質因數分解約 7 分、保齡球約 9 分。
  • 討論策略:先把「這是刻意選的平手局、為後面鋪墊」這個期待管理好,整集就穩了。質因數那段主打「測試序列一致」這個哲學洞見;保齡球那段主打「OO 的方便藏著耦合、FP 順手就分離了」這個對比。兩題都別陷進程式碼,講「結構差異」和「設計啟示」就好。
  • 結尾留個懸念:「這兩局打平,但下一題是模擬問題、是真正的狀態機——那才是兩種風格開始真正分家的地方。」勾住聽眾追下一集。