好的註解不是重複程式碼,而是在更高的抽象層次上闡明意圖(Intent)。程式碼本身是最可靠的文件——它隨著程式持續更新、永不過時。然而,光靠程式碼無法傳達所有資訊,因此我們需要在好的程式風格之上,再加上有效的註解來完善文件化工作。
32.1 外部文件#
外部文件(External Documentation)是指存在於原始碼之外的資訊,通常為獨立文件或開發資料夾。
- 單元開發資料夾(Unit Development Folder, UDF):非正式文件,記錄開發者在建構期間的設計決策軌跡。內容通常包含相關需求副本、頂層設計的對應部分、開發標準、目前程式碼清單以及開發筆記。
- 細節設計文件(Detailed-Design Document):描述類別層級或常式層級的設計決策、曾考慮的替代方案,以及最終選擇該做法的原因。有時以正式文件形式存在,有時只存在於 UDF 中,而很多時候——僅存在於程式碼本身。
32.2 程式風格即文件#
內部文件(Internal Documentation)是程式列表中最細粒度的文件。對程式碼層級的文件化而言,好的程式風格比註解更重要。程式風格包括:
- 良好的程式結構
- 直覺且易懂的實作方式
- 有意義的變數名稱與常式名稱
- 使用具名常數取代魔術數字
- 清晰的排版
- 最小化控制流程與資料結構的複雜度
當程式碼風格夠好時,它便能達到**自我文件化(Self-Documenting Code)**的境界——不靠註解也能清楚傳達意圖。此時註解只是可讀性蛋糕上的糖霜。
自我文件化程式碼檢查清單
- 類別:介面是否呈現一致的抽象?名稱是否描述核心目的?能否當作黑盒子使用?
- 常式:名稱是否精確描述行為?是否只執行一個定義明確的任務?
- 資料名稱:變數名稱是否有意義?迴圈計數器是否有描述性名稱?是否使用具名常數與列舉型別?
- 資料組織:是否使用額外變數提升清晰度?是否透過抽象存取常式處理複雜資料?
- 控制:正常路徑是否明確?巢狀是否最小化?布林運算式是否已簡化?
- 排版:程式的排版是否反映邏輯結構?
- 設計:程式碼是否直截了當、避免賣弄?是否盡可能以問題領域而非電腦科學術語撰寫?
32.3 註解或不註解#
關於註解的價值,書中以蘇格拉底式對話呈現了幾種立場:
- 反對派觀點:英文比程式語言更不精確;註解容易過時;大量註解反而增加閱讀負擔。
- 實務派觀點:好的註解不是重複程式碼,而是在更高的抽象層次闡明意圖。維護人員能透過掃描註解快速定位需要修改的區段,如同閱讀書中的標題或目錄。
- 折衷結論:鼓勵寫註解,但不天真看待。透過**程式碼審查(Code Review)**讓團隊建立對有效註解的共識。
當你發現註解與程式碼不一致時,通常代表兩者都有錯。註解的存在並非問題,糟糕的註解才是。
32.4 有效註解的關鍵#
註解的六種類型#
| 類型 | 說明 |
|---|---|
| 重複程式碼(Repeat of Code) | 用不同文字重述程式碼,毫無幫助 |
| 解釋程式碼(Explanation) | 解釋複雜或敏感的程式碼。通常代表程式碼本身應被改善 |
| 程式碼中的標記(Marker) | 如 TODO、FIXME,提醒開發者尚未完成的工作。應標準化標記格式以利全域搜尋 |
| 摘要(Summary) | 將數行程式碼濃縮為一兩句描述,讓讀者能快速掃描 |
| 意圖描述(Intent) | 解釋程式碼段落的目的,在問題層次而非解決方案層次運作。IBM 研究發現,維護人員最常說「理解原始開發者的意圖」是最困難的問題 |
| 程式碼無法表達的資訊 | 版權聲明、版本號、設計考量、相關文件的引用、最佳化說明等 |
對於完成的程式碼,只有三種註解是合理的:意圖註解、摘要註解、以及程式碼無法表達的資訊。
高效率撰寫註解#
- 使用容易維護的風格:避免需要對齊點線(
......)或右側星號欄的花俏格式。風格太精美就無人維護,最終變得不正確。 - 使用虛擬碼程式設計流程(Pseudocode Programming Process):先以虛擬碼撰寫大綱,再將其轉為註解並填入程式碼,一舉完成設計與註解。
- 將註解融入開發流程:不要拖到專案結束才寫。事後補寫需要回憶或重新理解程式碼,既費時又容易遺漏。
- 效能不是省略註解的理由:若註解影響效能(如早期 Basic、ASP、JavaScript),應透過建置工具在發行版本中剝離註解。
最佳註解密度#
IBM 研究顯示,大約每 10 行程式碼一條註解的密度是清晰度的高峰。過少難以理解,過多反而降低可讀性。與其追求數量,不如確保每條註解都有價值。
32.5 註解技術#
單行註解與行尾註解#
需要為單行程式碼加註解的情況很少見。行尾註解(Endline Comments)普遍存在對齊困難、空間有限、多數只是重複程式碼等問題,整體而言應避免。但有兩個合理例外:標註資料宣告(行尾註解在此最有價值)和標記長控制結構的結尾。不應用於維護記錄——那是版本控制系統的工作。
段落註解#
大多數好程式中的註解都是一兩句描述一段程式碼的段落註解。撰寫準則:
- 在意圖層次撰寫:描述「為什麼」而非「怎麼做」。好的註解如
// find the command-word terminator ($),而非// check each character in inputString。 - 先改善程式碼本身:用具名常數取代字面值、用有意義的變數名稱。
- 為讀者做準備:讀者應能只掃描註解就掌握程式碼的全貌。
- 記錄驚喜與變通做法:非直覺的技巧應註明原因與效能數據;繞過環境錯誤的做法應說明為何需要特殊處理。
- 不要為複雜程式碼加註解——重寫它:研究發現,註解密度最高的區域往往也是缺陷最多的區域。
若你必須問自己「這段程式碼算不算 tricky?」——它就是。永遠可以找到不需要技巧的重寫方式。先讓程式碼好到不需要註解,再用註解讓它更好。
資料宣告的註解#
資料的標註甚至比程序的標註更重要。要點:註明數值單位(或更好——嵌入變數名稱,如 distanceToSurfaceInMeters)、註明允許的數值範圍、註明編碼含義(優先使用列舉型別)、註明輸入資料限制、將旗標文件化到位元層級、在宣告處與使用處標註全域變數。
控制結構的註解#
- 在每個
if、case、迴圈或區塊之前加註解:說明控制結構的目的。 - 在長控制結構的結尾加註解:如
} // for clientIndex -- process each client,對深層巢狀特別有用。 - 將結尾註解視為警示:若一個迴圈複雜到需要結尾註解,考慮簡化它。
常式的註解#
避免在每個常式頂端堆砌過度冗長的「廚房水槽式」序言(Prolog)。過重的序言會阻礙程式碼的合理拆分——建立新常式的開銷太大,程式設計師寧可少建常式。
有效的常式註解準則:用一兩句話描述目的(無法簡短描述代表設計有問題)、在參數宣告處就地標註(行尾註解在此最合理)、善用 Javadoc 等文件擷取工具、區分輸入與輸出資料、記錄介面假設與常式限制、記錄全域效果與演算法來源。
類別、檔案與程式的註解#
- 類別:描述設計方針、使用限制與假設。確保類別介面的文件足以讓人不看實作就能使用。不要在介面文件中暴露實作細節。
- 檔案:描述檔案目的與內容。包含作者資訊、版本控制標籤與法律聲明。檔案名稱應與其包含的公開類別一致。
書本範式(Book Paradigm)#
Oman 與 Cook(1990)提出以書籍結構來組織程式碼文件:前言、目錄、章節、交叉引用。實驗結果顯示,採用書本範式的程式碼,維護任務的平均完成時間減少約 25%,理解分數提高約 20%。
32.6 IEEE 標準#
IEEE(電機電子工程師學會)軟體工程標準提供了原始碼層級以外的文件指引。主要分為三大類:
- 軟體開發標準:需求規格(IEEE 830)、設計描述(IEEE 1016)、組態管理(IEEE 828)、使用者文件(IEEE 1063)、維護(IEEE 1219)等。
- 軟體品質保證標準:品質保證計畫(IEEE 730)、軟體審查(IEEE 1028)、單元測試(IEEE 1008)、測試文件(IEEE 829)等。
- 管理標準:專案管理計畫(IEEE 1058)、生產力度量(IEEE 1045)、風險管理(IEEE 1540)等。
頂層標準為 ISO/IEC 12207(軟體生命週期流程),定義了開發與管理軟體專案的生命週期框架。
更多資源#
- Spinellis, Diomidis. Code Reading: The Open Source Perspective (2003):程式碼閱讀技巧的實用指南。
- Sun Microsystems. “How to Write Doc Comments for the Javadoc Tool” (2000):目前最完整的程式碼層級文件標準。
- McConnell, Steve. Software Project Survival Guide (1998):中型商業專案所需的文件描述。
- IEEE Software Engineering Standards Collection, 2003 Edition:包含 40 項 ANSI/IEEE 軟體開發標準。
要點#
- 註解是否有價值是合理的問題。做得差會浪費時間甚至有害,做得好則非常值得。
- 原始碼應包含程式的大部分關鍵資訊——只要程式仍在運行,原始碼比任何其他資源更可能保持最新。
- 好的程式碼本身就是最好的文件。 若程式碼糟到需要大量註解,應先改善程式碼。
- 註解應該說出程式碼無法自己說的事——在摘要層次或意圖層次。
- 某些註解風格需要大量瑣碎的排版工作,應發展出容易維護的風格。