程式碼潔癖系列(二):命名的藝術
- 2020 年 3 月 11 日
- 筆記
不知道大家還記不記得《家有兒女》里有這麼一段經典台詞:「我叫夏雪」,「我叫夏雨」,「我叫夏冰雹」。

劉星自己給自己起的名字承包了我所有笑點。但仔細想想這名字取的竟然還挺不錯,不但有意義,還和夏雨夏雪的名字相呼應。
回到主題,在我們的程式碼里,命名是隨處可見的,比如給包命名,給類命名,方法名,參數名,變數名等等。那麼什麼樣的命名才算是好的命名呢。這就是我們今天要討論的。
名副其實
首先還是要強調這一點,我讀過的糟糕的程式碼有一個共同的特點,那就是程式碼中存在大量隨意的,無意義的命名。比如:表示消耗多少小時的變數命名為h,同作用域中還有一個想要表示「小時」相關的變數直接命名為h1,一個List類型的變數就命名為list。讀這種程式碼不會令人開心,同時寫這種程式碼的程式設計師的人身安全是無法保證的。
public List<String> getThem() { List<String> list = new ArrayList<>(); for (String key : keys) { if (theMap.get(key) == 1) { list.add(key); } } return list; }讀一下上面這段程式碼,能看出有什麼問題嗎?或者說看完有人明白這段程式碼要做什麼嗎?
我先來說一下我的問題:
getThem是get什麼?
list里存的是什麼
keys指的是什麼,為什麼遍歷它
常量」1「的意義是什麼
這幾個問題可能只有寫這段程式碼的人才能解釋(沒錯,就是我寫的)。所以我來給大家解釋一下,不過我不想一一回答上面的問題,我把程式碼重寫一遍,看看還會不會有這樣的問題。
public List<String> getPaidOrderIds() { List<String> paidOrderIds = new ArrayList<>(); for (String orderId : orderIds) { if (orderStatus.get(orderId) == OrderConstatn.PAID) { paidOrderIds.add(orderId); } } return paidOrderIds; }怎麼樣,上面的問題都清楚了嗎,如果不清楚可以私下和我聯繫,我會給你推薦一個非常好的英語學習軟體。
這就是名副其實的重要性。
避免誤導
命名過程中要注意的第二點就是要避免名稱對別人產生誤導,例如上面程式碼中paidOrderIds這個變數,如果我們命名成paidOrderIdList呢,看起來似乎沒什麼問題,但是如果這個變數是Set類型或者其他類型呢?命名為xxxList還合適嗎,別人讀程式碼的時候會下意識的認為這是個List類型的變數(盡量避免名稱中出現類型的名字)。
另一點容易產生誤導的是數字和字母相像的情況,比如,我命名一個變數叫做O1,在編輯器里就很難分辨是O1還是01,如果我寫一個這樣的表達式
O0=l1;
估計別人會以為我發明了什麼新的語言吧。
第三點是要避免區別較小的兩個名稱,比如XYZContinentController和XYZCentinentController這樣的命名,對於讀程式碼的人來說簡直就是災難,對於寫程式碼的人來說也存在很大的風險。(為什麼不是災難?因為大部分人都是Ctrl+C/Ctrl+V的,這樣就減小一些出錯的幾率。看來善用Ctrl+C/Ctrl+V還是很有必要的)
做有意義的區分
編譯器要求我們在同一個區域內不能重複命名。那麼有的程式設計師就會寫出a1,a2,a3……這樣的命名,這看起來很爛,誰也不知道它們有什麼區別。再舉過來一個栗子,一個包中有兩個類,Product和ProductInfo,這時讓你查一下商品名稱,你知道要去哪個類里找嗎?事實證明,這樣的命名與a1,a2,a3之流別無二致。
既然要做區分,為什麼不做些有意義的區分呢,一個類叫做Product,表示商品資訊,另一個叫做ProductStocks表示商品的庫存資訊。這樣是不是更清晰一點呢,當然,我這裡只是舉個栗子,實際上可能不需要這樣定義。
別隨意使用簡寫
不要隨意使用簡寫,除非是大家都知道的簡寫。比如美國的命名寫成US,大家都可以理解,而如果generateCode寫成genCode就令人費解了。
使用可以被搜索的名稱
像我們在一開始的那段程式碼,為什麼要把常量「1」寫成OrderConstatn.PAID,不僅是為了可讀,也是為了可搜索,試想,如果你要找這段程式碼,去搜索數字1,會有多少結果?搜索PAID呢?親自試過之後相信你會回來點贊的。
類名和方法名
類名和方法名也要遵循上面的規範,除此之外,它們還有各自的規範:、
類名不應該是動詞,避免使用Data、Info這樣的辭彙
方法名應該是動詞,比如,saveXXX、deleteXXX
要專一
假如你在不同的類中,分別定義了方法getXXX、fetchXXX和findXXX,我要調用的時候怎麼知道某個類中應該使用哪種方法?所以,為什麼不都用getXXX的形式呢?這樣無論是對寫程式碼的人還是對調用的人來說都是莫大的喜訊。
適當添加語境
當你一些變數:firstName、lastName、street、houseNumber、city、state、zipcode。我們可以很輕易的判斷出,他們組合在一起表示一個地址。那麼把state單獨拿出來呢?你還能知道它是什麼意思嗎?這時,我們可以把變數命名為addrState、addrFirstName……這樣即便單獨看某個變數,也會理解它要表達什麼。當然更好的方法是定義一個名為Address的類,把這些變數放到類中,事實上我們也都是這樣做的。
當然,有時候也不能添加一些無意義的語境。我們要開發一個「畫圖」的應用,那在每個類名前加Drawing可不是什麼好主意。
結語
命名並不能算是什麼技術,而是一種寫程式碼的習慣,但這種習慣有可能會決定你作為一名程式設計師給人的第一印象。所以,養成一個好的命名習慣,也是對自己形象的維護。同時還能讓自己的生命安全更有保障(避免被同事……

—END—
