註解是把雙面刃。多數註解的存在,其實是在彌補程式碼沒能把意圖說清楚的失敗。真理只存在於一個地方:程式碼。所以動手寫註解前先問——我能不能改個名字、抽個函式,讓程式碼自己說話?真正該留下的註解,是程式碼無論如何都表達不了的「為什麼」。
🧠 Why It's a Problem
- 註解不會跟著程式碼更新:程式碼被改、註解被遺忘,於是一段位置正確的註解會慢慢腐化成謊言。Code Complete 說得直接:當註解與程式碼不一致,通常兩者都錯了。
- 重述型註解是純雜訊:
i++; // increment i沒有增加任何資訊,只增加要維護的字。強制「每個函式都要 Javadoc」只會量產廢話。 - 好註解在更高的抽象層闡明意圖:它運作在「問題層次」而非「解法層次」。IBM 研究發現,維護者最難的事就是「理解原開發者的意圖」——這正是好註解該補的。
- 別給爛程式碼寫註解,重寫它:整潔具表達力的程式碼,遠勝錯亂又滿是註解的程式碼。註解只是可讀性蛋糕上的糖霜,不是蛋糕本身。
WARNING
嚴禁保留被註解掉的程式碼。 別人看到會不敢刪——怕它藏著什麼重要功能——於是它越積越髒。相信版本控制,直接刪。同理,日誌型註解(逐次改動記錄)與署名(// Written by Bob)都該交給 Git,不寫進原始碼。
⚖️ 好註解 vs. 壞註解
壞 — 註解在重述程式碼,或替爛命名擦脂抹粉
// 檢查使用者是否為成年人
if (u.a >= 18) {
// ...
}
// 迴圈跑過所有訂單
for (const o of orders) {
o.p = o.q * o.pr; // 計算價格:數量乘單價
}u.a、o.p/o.q/o.pr 靠註解翻譯才看得懂——但註解一旦沒跟上改名就成了謊言。這些註解在補命名的破洞。
好 — 命名消掉重述型註解,只留程式碼說不出的「為什麼」
if (user.age >= LEGAL_ADULT_AGE) {
// ...
}
for (const order of orders) {
order.price = order.quantity * order.unitPrice;
}
// SimpleDateFormat 非 thread-safe,因此每個執行緒各自建立實例,
// 不共用——這是為了避開已知的競態,別「優化」成共用單例。
const formatter = new Intl.DateTimeFormat("en-US");命名一到位,前面那些翻譯型註解全消失。唯一留下的註解解釋的是程式碼表面看不出的理由(為何不共用實例)——這種「為什麼」才值得寫。
NOTE
Clean Code 認可的少數好註解:法律聲明、對正則/特殊格式的資訊性說明、意圖解釋(為何這樣做)、後果告誡(thread-unsafe、耗時)、TODO(且要定期清)、以及對關鍵細節的放大強調(// trim 很重要)。共通點都是——補程式碼說不出口的東西。
🔑 Takeaways
- 註解常是「程式碼沒說清楚」的補丁;先試著用 命名 與 抽函式 讓程式碼自我說明。
- 該留的註解解釋為什麼(意圖、後果、權衡),而非重述做什麼。
- 重述型、強制型、日誌型、署名型註解都是雜訊——交給命名或 Git。
- 被註解掉的程式碼一律刪除,別讓它腐爛在檔案裡。
No notes yet — jot your takeaways or Q&A here.