第 6 / 7 部 待錄

重構案例與平行化之二

《Clean Code》Podcast 準備稿:平行化之二・三個重構實戰案例

書名: 無瑕的程式碼 Clean Code(A Handbook of Agile Software Craftsmanship) 作者: Robert C. Martin(Uncle Bob) 系列: Reading Uncle Bob(恩普拉氏) 公開標題建議: Reading Uncle Bob|Clean Code.實戰重構:整潔不是天賦,是反覆打磨 (6/7) 涵蓋範圍: 附錄A 平行化之二 + 第14章 持續地精煉 + 第15章 JUnit 內部結構 + 第16章 重構 SerialDate

背景速覽

這集把全書的「實戰案例」收在一起:附錄 A 是平行化的深入補充(效能瓶頸診斷、執行路徑爆炸、鎖定策略),第 14–16 章則是三個「看 Uncle Bob 真的動手重構」的案例(持續精煉的方法論、重構 JUnit 內部、重構 SerialDate)。前面五集講「原則」,這集講「原則怎麼落到手上」。

一句話重點

整潔程式碼不是一次寫成的天賦,而是「先求有、再求好」反覆打磨的習慣——而打磨的前提是有測試當安全網;連 JUnit、SerialDate 這種大師級的開源 code 都有改進空間,你日常的商業邏輯當然更值得回頭精煉。

值得討論的重點

1.(附錄A 平行化之二)上並行前,先問「瓶頸在哪」

  • 效能診斷先行:I/O bound(等 socket/DB)→ 並行有用(一個 thread 等待時別人用 CPU);CPU bound(重計算/GC)→ 並行救不了,甚至因 context switch 更慢,得靠演算法或硬體。
  • 單行 code 不是單一動作++lastIdUsed 在 bytecode 層是「讀-改-寫」多步,多執行緒會在指令間隙穿插→資料不一致;加 synchronized 把路徑數從天文數字收斂、保證原子性。
  • 鎖定策略:容忍錯誤(僅非關鍵)/客戶端鎖定(不推,呼叫者會忘)/伺服器端鎖定(推薦,把鎖封裝進類別內部)。了解工具:Executor 執行緒池、NIO/CAS 非阻塞、內建執行緒安全類別。

2.(持續精煉)整潔是「習慣」不是「天賦」

  • 沒人一次寫出完美 code;資深工程師也是先寫出能跑的爛初稿,再回頭整理(像寫作:粗稿→反覆修飾→定稿)。
  • TDD 是安全網:要求系統隨時可運作;有完整測試,你才有勇氣大改。
  • 忽視重構的代價:「之後有空再改」的那個「之後」永遠不會來;爛 code 會發酵腐敗、逼新 code 也配合混亂,最後拖垮團隊。

3.(JUnit/SerialDate 兩個重構案例)大師的 code 也能更好

  • Uncle Bob 拆解 Kent Beck & Eric Gamma 寫的 JUnit ComparisonCompactor、和 David Gilbert 的 SerialDate——示範專業的 code review 與重構長什麼樣
  • 方法論:先補足單元測試(建安全網)→ 重構(改名、拆長函式、移死 code、修抽象層級)→ 驗證
  • 心態:「這不是關於對與錯,而是關於好與更好」;重構是一連串 try-and-error(改了不如預期就 rollback 再試)。

注意事項

⚠️ 這幾章在 Podcast 上最難講——因為它們是「看著 Java 程式碼一步步改」,沒有畫面很吃力。 建議不要試圖口頭重現程式碼,而是抽出「方法論與心法」:先補測試、小步重構、可回退、追求「好與更好」。把案例當「精神示範」講,而非逐行 walkthrough。

⚠️ 附錄 A 的並行內容和第 13 章高度重疊,別重複講太多。重點挑「I/O vs CPU bound 決定該不該並行」「單行 code 其實是多步」「伺服器端鎖定 > 客戶端鎖定」三個有記憶點的洞見即可。

⚠️ Uncle Bob 重構 SerialDate 那段,業界其實有過反彈——有人覺得他對 David Gilbert 原作的某些「改進」見仁見智、甚至引發過公開討論。可以誠實提一句:重構帶有主觀品味,「好與更好」這句話本身就承認了沒有唯一正解。這反而是健康的態度。

專家補充

💡 「先求有、再求好」可以連到一個更大的工程智慧——「先讓它能動,再讓它對,最後讓它快(Make it work, make it right, make it fast)」(Kent Beck)。順序很重要:別在還沒對之前就過早優化(premature optimization is the root of all evil — Knuth)。這把本集接到兩句工程界的鎮山名言。

💡 「之後再改的『之後』永遠不會來」其實有個正式名字——技術債(Technical Debt)(Ward Cunningham 提出的隱喻)。沒還的技術債會以「利息」的形式拖慢每一次後續開發。這個隱喻很適合在節目裡展開,也呼應書庫裡的相關書。

💡 重構案例的價值,正是《Refactoring》(Fowler) 整本書的主題——Clean Code 給你「目標(什麼是乾淨)」,Refactoring 給你「手法(一步步怎麼安全地改)」與正式的「壞味道型錄」。本集最適合預告 Fowler《Refactoring》這本旗艦大書。

討論問題

🎙️ 開場鉤子:「你有沒有看過資深工程師寫 code 的『第一版』?通常也很醜。差別不在初稿,在於他們會回頭改——而大部分人不會。」

🎙️ 自問自答:「『這段很髒,我之後有空再改』——這句話你說過幾次?那個『之後』來過嗎?」直接戳技術債的痛點。

🎙️ 帶走的一題:「挑一段你三個月前寫的、現在看了會皺眉的 code。先確認它有測試(沒有就補一個),然後小步重構它——體驗一次『有安全網的重構』有多踏實。」

更大範圍關聯

  • Refactoring(Fowler):本集最佳延伸——Clean Code 講目標,Refactoring 講手法與壞味道型錄。系列旗艦大書。
  • Working Effectively with Legacy Code(Feathers):「想重構但沒測試的舊 code 怎麼辦」的專書,正好補本集「先補測試」的難題。
  • 技術債:Ward Cunningham 的隱喻;接 Martin Fowler 的 technical debt quadrant。
  • TDD(Kent Beck):持續精煉的安全網來源;JUnit 正是 Beck 的作品,本集等於致敬。

錄製建議

  • 建議時長:約 20 分鐘。並行之二約 7 分、持續精煉約 7 分、兩個重構案例合併約 6 分(講方法論不講 code)。
  • 討論策略:這集的賣點是「從原則到實作」——前五集講道理,這集看大師動手。但因為案例是 Java code,務必把案例抽象成心法(先補測試、小步可回退、好與更好)。用「技術債」「之後永遠不會來」這些有情感重量的概念承載,比講程式碼細節更適合音訊。結尾大力預告下一集(全書收官)的「壞味道大全」,和系列下一本《Clean Architecture》。
  • 單人主講時,「I/O vs CPU bound」那張表、「技術債」隱喻是最好帶走的兩個點。