🎯 什麼情境該想到我
分工:這張是語言無關的命名判準與流程。Go 特有的規則(套件名幫你省字、Getter 不加 Get、
-er介面、縮寫全大寫)→ 工具-Go命名慣例;把爛名字改好的重構步驟 → 神秘命名。
當你在替變數/函式/類別取名字,或看到一堆 d、tmp、data 看不懂時。
⚙️ 怎麼用
- 名字要能回答:它是什麼、為何存在、怎麼用。看到名字就不用再看註解。
- 用可讀、可搜尋的名字:
elapsedTimeInDays勝過d;避免單字母(迴圈計數例外)。 - 別用誤導性名字、別加型別雜訊(匈牙利命名法過時)。
- 類別用名詞、函式用動詞;同一概念用同一個字(別 fetch/get/retrieve 混用)。
★ 名字長度 ∝ 使用處與宣告處的距離
這是最常被誤解的一條——「名字要有意義」不等於「名字要長」:
| 作用域 | 讀者看到名字時,宣告在哪? | 合適的名字 |
|---|---|---|
| 3 行的迴圈 | 就在上一行 | i、k, v、r(for _, r := range rows) |
| 20 行的函式區域變數 | 同一個螢幕 | total、buf、cfg |
| 套件層級/匯出 | 可能在另一個檔案、另一個 repo | DefaultRetryPolicy、ErrQuotaExceeded |
同一個概念在小範圍用長名字反而是雜訊:for index, currentRowValue := range rows 比 for i, r := range rows 難讀。所以命名問題有一半要靠 工具-縮小變數作用域 解決——作用域縮小了,短名字就合法了。
★ 命名的四步流程(卡住時照做)
- 先說出它是什麼:用一句完整的話描述它,「這是還沒被付款的訂單的數量」。
- 從句子裡挑名詞/動詞:
unpaidOrderCount。 - 刪掉讀者從上下文就知道的字:在
package order裡 →unpaidCount;在func (s *Stats)的方法裡已經很清楚 → 可能只要unpaid。 - 說出來測試:唸給同事聽,對方能不能不看程式碼就猜到它是什麼?會不會跟另一個東西搞混?
第 1 步說不出來,就是設計問題而非命名問題——這個東西可能同時做了兩件事,或根本不該存在。
★ 一眼可認的壞名字
| 壞名字 | 問題 | 改法 |
|---|---|---|
data、info、item、obj | 什麼都是,等於什麼都沒說 | 說它是什麼資料:invoice、quote |
Manager、Helper、Util、Processor | 職責不明的收納箱,會一直長大 | 拆開,各自用具體動作命名 |
flag、status 配 true/false | 讀呼叫端完全看不懂 | isRetryable、hasShipped |
notDisabled、!isNotValid | 雙重否定 | 一律用正向:isEnabled、isValid |
timeoutMs int、sizeKB int | 單位靠名字記,會被搞錯 | 用型別:Go time.Duration;TS 用 branded type 或物件 { ms: number } |
同一概念 fetch/get/load/retrieve 混用 | 讀者會以為它們行為不同 | 全專案一個動詞對一個語義(例如 Get = 讀快取、Fetch = 走網路),寫進 工具-通用語言 |
★ 改名要靠工具,不要靠搜尋取代
- Go:
gopls的 rename(編輯器 F2)以型別資訊找出所有引用,連跨套件、介面實作都會改;sed會連字串和註解裡的同名字一起改爛。 - TS:編輯器的 Rename Symbol 同理。
- 匯出的名字改名 = 破壞 API。對外套件先加新名字、舊名字標
// Deprecated: use X.再過一個版本刪。
🧪 我實際套用的紀錄
- 2026-07-14:(待填)
⚠️ 注意
-
想不到好名字,往往代表那段職責不清 → 該先釐清設計,命名是設計的鏡子。
-
別為了「可搜尋」把所有名字都拉長:可搜尋性只對大作用域的名字有意義;區域變數沒人會全域搜尋。
-
縮寫只用團隊公認的:
ctx、req、cfg大家都懂;calcAmtWTx只有作者懂。
🔗 相關工具
- 工具-函式短小且單一職責 —— 取不出好名字通常是職責不清;把函式切到只做一件事,名字往往自己浮出來
- 工具-縮小變數作用域 —— 降低閱讀心智負擔的另一半:作用域夠小時,短名字不但無妨還更好讀