🎯 什麼情境該想到我

當你「踏進一份陌生的舊程式碼,光用眼睛讀怎麼讀都讀不懂,也沒有文件、沒人能問」的時候。

書講得很直白:很多人不肯用其他辦法,是因為他們正忙著想盡快把程式碼看懂——「把時間花在理解某某東西上面感覺就好像不是在用心工作一樣。要是可以迅速完成理解的過程,就可以接著投入『真正的』工作了」(p.172)。書說這麼想不對,因為他們「本可以只需花上一點點低技術含量的工夫就可以讓自己後面的工作處於一個更堅固的基石上了」(p.172)。

⚙️ 怎麼用

書分成兩層:看不懂「某一段碼」(第 16 章)和 看不懂「整個系統」(第 17 章)。

A. 看不懂某段程式碼(第 16 章,四招)

1. 註記/草圖(16.1,p.172)

「如果閱讀程式碼還是搞不清的話,你可以畫草圖並作一些註記。把最近看到的重要的地方寫下來。如果你看到它們之間存在著某個聯繫,就在它們之間畫一條線。」(p.172)

  • 不必是 UML 或函式呼叫圖那種正式東西;書中那張圖是作者「畫在一個備忘錄的反面的」(p.172)。
  • 事情真的變複雜了,再考慮「把圖畫得正式、乾淨一點」(p.172)。
  • 它的價值有兩個:「幫助我們從另一個角度來看待問題」、以及在理解特別複雜的東西時「對於記錄我們的思考狀態也是極有幫助的」(p.172)。
  • 推廣方式是傳染而不是強迫:「根本無需強迫你的團隊去使用它,你所需做的就是,等到你去協助某個希望理解某塊程式碼的人的時候,在解釋的時候通過畫草圖來幫助你解釋程式碼的意思」(p.173)。

2. 清單標註(16.2,p.173)
第一步是把程式碼印出來(p.173),然後照你「到底想要理解什麼」選標註方式:

你想幹嘛書給的標註手法
分離職責用一個記號把屬於一起的幾段/幾行圈成同一組,「可能的話,使用多種顏色」p.173–174
理解一個很長的方法把程式碼區塊對齊:從區塊開頭到結尾畫一條線,或在結尾用註解標明它對應哪個條件語句/迴圈。對齊的最簡單辦法是從內到外——往下讀,遇到第一個結束處先標記,再回溯標記與它配對的開頭,然後繼續p.174
想拆掉長方法把想提取出來的程式碼圈起來,並註上它的耦合數p.174
想知道改動會影響什麼在準備改的那行旁做記號 → 在每個可能被它影響的變數和方法呼叫旁做記號 → 再往外一層……「盡量多做幾次直到你看清影響是如何從修改點傳播開來的」p.174

最後一項書直接說了報酬:「通過這一過程,你就會對自己所需要測試的東西有一個更好的認識」(p.174)。

3. 草稿式重構(16.3,p.174)

「認識程式碼的最佳技術就是重構。你走進程式碼,一番搗鼓之後,程式碼變得更清晰了。」(p.174)

做法:從版本控制系統取出程式碼,別去管測試,只管提取方法、搬移變數,用你喜歡的方式重構——「但這麼做了之後你可得記住別再把這些程式碼輸入到伺服器上去了」(p.174)。就是丟棄式的。作者說同事原本覺得浪費時間,「但半個小時之後他的看法完完全全改變了」(p.174)。

4. 刪除不用的程式碼(16.4,p.175)

「如果你正在看的程式碼讓你感到迷惑,而且你敢斷定這段程式碼中有些部分並沒有被使用到,那麼就刪掉它們吧。它們除了擋路之外沒帶來任何正面效應。」(p.175)

覺得刪掉可惜?「版本控制系統正是替你做這事情的」(p.175)。

B. 看不懂整個系統(第 17 章,三招)

先認清阻礙。書列了團隊搞不懂自己架構的三個原因(p.176):系統太複雜、要有整體認識得花很長時間;系統太複雜、乃至於根本沒有所謂的整體認識;團隊「就像繃緊的彈簧一樣,光顧著埋頭解決一個又一個的緊急情況」。

而且不能只靠架構師:「架構師不是少數人所專有的,而必須是大家的」(p.176)。書給的算術很直接——20 人的團隊只有 3 人懂架構細節,「則要麼這 3 人需要多做許多額外的工作來讓其餘 17 人都能夠跟上,要麼就等著其餘 17 人因對大局不熟而犯錯誤吧」(p.177)。

5. 講述系統的故事(17.1,p.177)
至少要兩個人。像唱雙簧那樣,一個人問「該系統的架構是怎樣的?」,另一個人回答——「他應該盡量只使用兩到三個概念就把系統的架構解釋清楚」(p.177)。假設對方對系統一無所知,用寥寥數句講清楚設計由哪些部分構成、它們之間如何互動;講完最本質的,再選第二重要的,直到核心設計都說明白(p.177)。

會很不舒服,這是正常的:你簡化著講的時候,「你可能會感覺自己在撒謊似的,因為你覺得自己並沒有把事情說全面」(p.177)。但書說重點在於——「你講的這個簡化版本能夠描述一個易於理解的架構」(p.177),而且它「能強迫你去思考系統當中重要的東西是哪些」(p.177)。

它的實際用途是當選型的尺:在考慮修改時,「你會注意到其中有些修改與你們講述的故事更為一致」;有兩種方式達成同一目標時,「系統的故事就能夠幫助你判斷出哪種方式能夠導向一個更易理解的系統」(p.178)。書用一個測試框架的例子演示了整輪操作:先講一段簡短描述,再逐條列出「這段描述省掉了什麼」,然後拿兩種加新特性的方案去對照哪個讓故事變得更不真實(p.178–180)。

還有兩個附帶好處:這個簡單「故事」「就像是有了一個路標一樣,當你想要弄清哪兒才是添加一個特性的正確地點時它能夠幫你指明方向。而且,它還能夠消除你對系統的畏懼感」(p.177)。

6. Naked CRC(17.2,p.180)
CRC 是「類(Class)」「職責(Responsibility)」「協作(Collaboration)」(p.180)——原本是在索引卡片上寫下類名、職責、以及與它互動的類(p.180)。Naked CRC 則是「除了不是把東西寫在卡片上之外,它幾乎跟 CRC 一樣」(p.180–181)。

做法:描述系統的人「使用一組空白的索引卡片,把它們一個個攤在桌上」,靠移動卡片、指卡片等動作,來傳達系統中的典型物件以及它們之間如何互動(p.181)。書示範了用它講一個線上投票系統:邊擺卡片邊說「每個會話上都有兩個連接,一個接入,一個接出」、「當一個伺服器端會話發起時,它會向選票管理器註冊」……(p.181)。

為什麼有效:「它使得一個系統的各部分成為真實可觸摸的東西。關鍵在於,藉助卡片,你可以使用肢體動作來表達系統的各部分之間是如何互動的。這往往能令複雜的場景變得更易掌握。」(p.182)

兩條原則(p.182):

  1. 卡片代表實例,而非類;
  2. 疊在一起的卡片來表示「一組實例」。

7. 反省你們的交流或討論(17.3,p.182)

「聽聽那些關於你們的設計的討論。你們在交流過程中使用的概念與實際出現在程式碼中的概念是一樣的嗎?」(p.183)

書舉的例子:團隊討論了半天「資源加鎖/解鎖策略」,卻有人直接把碼塞進既有程式碼、用陣列存計數——作者說「等等,不就是鎖策略嗎?幹嘛不創建一個 LockingPolicy 類,然後在它裡面維護計數器呢?」(p.183)。

若討論用的概念和程式碼裡的概念對不起來,答案「往往由兩部分構成:程式碼不允許被修改成那團隊的理解一致的樣子,或者團隊需要換個角度去理解它」(p.183)。書的收尾是一句話:「人們在談論設計時會努力試圖讓其他人理解被談論的設計。放一些理解在程式碼裡面吧。」(p.183)

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 草稿式重構有兩個風險(p.174–175):一是「我們在重構的時候可能會犯一些惡劣的錯誤,從而使得我們誤解程式碼的行為」,這種錯誤認識之後真正重構時會來找麻煩;二是重構完之後「我們的思維可能就會固定在重構出來的系統的樣子上了」,日後可能因此「錯過許多很好的想法」。
  • 草稿式重構的產出不可入庫:書明講「你可得記住別再把這些程式碼輸入到伺服器上去了」(p.174)。
  • 系統的故事一定是簡化的、也一定不完整——這不是問題。「如果系統實際上並不像我們把它簡化成的那樣,是不是就意味著什麼糟糕的事情呢?不是的。一個系統在不斷成長的過程中總會變得越來越複雜。我們的簡化描述只是為了給自己引路。」(p.179)
  • 而且要「試著以多種不同的方式來講述」(p.178);同一個系統別人可能有「一個不同但同樣有效的認識」(p.178)。
  • 草圖不必求正式,UML 沒有錯,但「圓圈和線條,還有那些不在場人就無法理解的各種形狀的圖形也是有用的。圖只是工具」(p.173)。
  • 要做局部草圖之前,先看整體:「當開始要給一個系統做局部草圖的時候,通常你可能會想先花點時間來從整體上理解系統」(p.173)——也就是先做 B 組再回頭做 A 組。
  • 第 17 章這些技巧要常常做才有用:「如果你常在團隊裡實踐這些技術,就會發現它們能夠使你的團隊始終保持對架構的關注……因為通常我們很難對不常想到的事情保持關注」(p.177)。
  • 沒有速效解:面對「應用毫無結構可言」這種狀況,「並沒有什麼輕而易舉的解決辦法」(p.176)。

🔗 相關工具

  • 工具-遺留程式碼修改流程 —— 理解只是起手式,整套改動流程在這裡
  • 工具-影響分析 —— 讀懂之後才有辦法判斷改動會傳播到哪;書把「在程式碼上做記號追影響」直接列為理解手法之一(p.174)
  • 工具-特徵測試 —— 用測試把現況行為逼出來,也是一種理解手段
  • 工具-心智圖 —— 同屬「畫出來以建立整體認識」的手法,可與註記/草圖搭配