註解是程式碼品質的警訊#

本章討論的是方法內部的註解,不包含 Javadoc 之類供外部工具使用的文件。

Rob Pike 早在 1989 年就指出:如果程式碼夠清晰、命名夠好,它應該能自我解釋。註解不受編譯器檢查,容易在修改後失去同步,而誤導性的註解比沒有註解更危險。Martin Fowler 則將註解列為 code smell,認為它們常被當作「程式碼除臭劑」——與其在臭程式碼上噴香水,不如直接清洗乾淨。

Kevlin Henney 的原則:「只為程式碼無法表達的事情寫註解(Comment only what the code cannot say)。」

本章將註解分為五類,從最容易處理到最困難,依序討論。

flowchart TD
    Start["遇到註解"] --> Q1{"過時或不正確?"}
    Q1 -->|是| DEL1["刪除"]
    Q1 -->|否| Q2{"被註解掉的程式碼?"}
    Q2 -->|是| DEL2["刪除"]
    Q2 -->|否| Q3{"顯而易見?"}
    Q3 -->|是| DEL3["刪除"]
    Q3 -->|否| Q4{"描述接下來的程式碼?"}
    Q4 -->|是| EXT["抽取為方法\n用註解當方法名稱"]
    Q4 -->|否| Q5{"記錄不變量?"}
    Q5 -->|是| Q6{"能用型別或測試取代?"}
    Q6 -->|是| REP["用型別或測試取代"]
    Q6 -->|否| KEEP["保留註解"]

    style DEL1 fill:#c8e6c9
    style DEL2 fill:#c8e6c9
    style DEL3 fill:#c8e6c9
    style EXT fill:#bbdefb
    style REP fill:#bbdefb
    style KEEP fill:#fff9c4

第一類:刪除過時的註解#

過時的註解包括已經不正確或具有誤導性的內容。它們曾經正確,但隨著程式碼演進而失去同步。

嚴重程度後果
最輕微浪費閱讀時間
中等誤導開發者設計出錯誤的程式碼
最嚴重直接導致 bug

例如,註解寫著「has a selection and allows multi selection」,但條件判斷用的是 ||(or)——這種不一致會造成危險。

處理方式:直接刪除。

第二類:刪除被註解掉的程式碼#

開發過程中,暫時將程式碼註解掉來實驗是合理的。但實驗結束後,被註解掉的程式碼應該被刪除,因為版本控制系統隨時可以還原。

正確的實驗流程是:

  • 在 Git 建立分支
  • 刪除舊程式碼、撰寫新程式碼
  • 成功就合併,失敗就丟棄分支

處理方式:直接刪除,需要時從版本歷史還原。

第三類:刪除顯而易見的註解#

當程式碼本身和註解一樣容易閱讀時,這個註解就是多餘的(trivial)

例如,在 Logger.error(errorMessage, e) 上方寫 /// Log error——這完全沒有增加任何資訊量。同樣地,如果一個註解在瀏覽程式碼時總是被跳過,它就只是在佔空間。

處理方式:直接刪除。

第四類:將註解轉化為方法名稱#

有些註解描述的是接下來那段程式碼在做什麼。例如:

/// Build request url
if (queryString)
  fullUrl += "?" + queryString;

這種情況下,應該將那段程式碼抽取為方法,用註解的內容作為方法名稱。抽取後原來的註解就變成顯而易見的,可以刪除。

有人不喜歡太長的方法名稱,但這只有在頻繁呼叫的方法上才是問題。就像自然語言一樣——越常用的詞越短,程式碼庫也應該如此。

以註解做規劃是好習慣#

在開發時用註解列出計畫步驟(如 /// Fetch data/// Transform)是很好的做法。但程式碼寫完後,必須審視這些註解是否仍有價值——有些會變成顯而易見的註解,有些應該轉化為方法名稱。

第五類:保留記錄不變量的註解#

最後一類是記錄**非局部不變量(non-local invariant)**的註解。辨識方法是問自己:「這個註解是否能防止某人引入 bug?」

例如:

/// Log off used to force re-authentication on next request
session.logout();

身份驗證的交互行為極難測試或模擬,這樣的註解完全合理。

遇到這類註解時,仍應依序嘗試:

  1. 能否用編譯器(型別系統)取代?
  2. 能否用自動化測試驗證?
  3. 以上都不可行,才保留註解

流程中的不變量#

TODOFIXMEHACK 也是一種不變量——不是程式碼的不變量,而是開發流程的不變量。有人主張它們應該放在工單系統而非程式碼中,這確實有道理。但如果選擇放在程式碼裡,就應該:

  • 有視覺化方式追蹤數量
  • 數量必須持續下降
  • 目標是真正修復問題,而不是無限期推遲

註解在開發過程中非常有用,但應在交付前的重構階段處理。交付的每一行註解,都應該先問過自己:「有沒有更好的方式表達它所說的事?」