一文搞定代碼中的命名
導(dǎo)語(yǔ)
Phil Karlton 曾經(jīng)說(shuō)過(guò):計(jì)算機(jī)科學(xué)領(lǐng)域只有兩件難事:緩存失效和命名。而命名又是寫(xiě)出整潔代碼基礎(chǔ)中的基礎(chǔ),本文的副標(biāo)題其實(shí)是《關(guān)于命名的讀書(shū)筆記》,自己在學(xué)習(xí)過(guò)程中的整理出來(lái)一點(diǎn)心得筆記,共勉!
為什么要做好命名?
任何一個(gè)傻瓜都能寫(xiě)出計(jì)算機(jī)可以理解的代碼。唯有寫(xiě)出人類容易理解的代碼,才是優(yōu)秀的程序員?!?Martin Fowler 整潔的代碼如同優(yōu)美的散文?!?Grady Booch 程序?qū)懗鰜?lái)是給人看的,附帶能在機(jī)器上運(yùn)行。–《計(jì)算機(jī)程序的結(jié)構(gòu)與解釋》
讀懸疑偵探類小說(shuō),透過(guò)神秘的文字推測(cè)故事情節(jié)是個(gè)挺不錯(cuò)的體驗(yàn)。但是如果是在閱讀代碼,這種體驗(yàn)會(huì)讓你淚奔。
做好命名很難
起名字這件事看似不難,但是要經(jīng)過(guò)深思熟慮,取出名副其實(shí)、表達(dá)性好的名字并不是一件很容易的事。
命名為什么難呢?因?yàn)槊倪^(guò)程本身就是一個(gè)抽象和思考的過(guò)程,在工作中,當(dāng)我們不能給一個(gè)模塊、一個(gè)對(duì)象、一個(gè)函數(shù),甚至一個(gè)變量找到合適的名稱的時(shí)候,往往說(shuō)明我們對(duì)問(wèn)題的理解還不夠透徹,需要重新去挖掘問(wèn)題的本質(zhì),對(duì)問(wèn)題域進(jìn)行重新分析和抽象,有時(shí)還要調(diào)整設(shè)計(jì)和重構(gòu)代碼。因此,好的命名是我們寫(xiě)出好代碼的基礎(chǔ)。
就像Stack Overflow的創(chuàng)始人Joel Spolsky所說(shuō)的:“起一個(gè)好名字應(yīng)該很難,因?yàn)橐粋€(gè)好名字需要把要義濃縮在一到兩個(gè)詞中。(Creating good names is hard, but it should be hard,because a great name captures essential meaning in just one or two words.)“
此外,Martin Fowler也表示過(guò),他最喜歡的一句諺語(yǔ),就是我們的導(dǎo)語(yǔ)中提到的那句話:“在計(jì)算機(jī)科學(xué)中有兩件難事:緩存失效和命名。(There are only two hard things in Computer Science:cache invalidation and naming things.)”
變量命名
1)好的命名的注意事項(xiàng)
1.1)命名要名副其實(shí)
這是為變量命名時(shí)最重要的考慮選項(xiàng)。名字要完全、準(zhǔn)確的描述出該變量代表的事物。
最簡(jiǎn)單的方法是用文字描述變量所表達(dá)的含義,對(duì)變量的描述就是最好的變量名。這種名字很容易閱讀,因?yàn)樗话菀谆逎目s寫(xiě),同時(shí)也沒(méi)有歧義。因?yàn)樗麑?duì)代表的事物做了完整描述,因此不容易混淆。
如描述運(yùn)動(dòng)場(chǎng)中座椅數(shù)數(shù)量,number_of_sets_in_the_stadium
備注: 本文命名都以python的命名方式書(shū)寫(xiě),其他語(yǔ)言的根據(jù)語(yǔ)言命名格式轉(zhuǎn)換即可。
如果有一種變量你沒(méi)法描述,那么說(shuō)明你可能要重新思考業(yè)務(wù),思考邏輯。
1.2)以問(wèn)題為導(dǎo)向
好記的名字往往反映的通常都是問(wèn)題,而不是解決方案。好的名字通常表達(dá) what ,而不是 how ,如果名字反映了計(jì)算的某些方面而不是問(wèn)題本身,那么它反映的就是 how 而不是 what。
舉例子說(shuō)明一個(gè)員工的數(shù)據(jù)記錄,input_rec 或者 employee_data ,input_rec 反映的就是輸入記錄這些計(jì)算機(jī)學(xué)術(shù)用語(yǔ)。employee_data 則直指問(wèn)題。那么 employee_data 就是個(gè)好名字。
1.3)最佳的命名長(zhǎng)度
變量名的最佳長(zhǎng)度似乎應(yīng)該介于 n 和 number_of_sets_in_the_stadium 之間。太短的名字無(wú)法傳達(dá)足夠的信息。太長(zhǎng)的名字很難寫(xiě),同時(shí)還會(huì)使程序視覺(jué)結(jié)構(gòu)變得模糊不清。
國(guó)外的大佬 Gorla、Benander 研究發(fā)現(xiàn),當(dāng)變量名平均在 10 到 16 個(gè)字符的時(shí)候,調(diào)試程序所花費(fèi)的時(shí)間最小,平均名字長(zhǎng)度在 8 到 20 個(gè)字符的時(shí)候也很適合調(diào)試。這項(xiàng)原則并不是要求你一定要把變量控制在 8 到 16 的長(zhǎng)度。它強(qiáng)調(diào)的是如果你查看自己寫(xiě)的代碼時(shí)發(fā)現(xiàn)很多更短的名字,你需要好好斟酌,確保這些名字是否足夠清晰表達(dá)其含義。
太長(zhǎng): number_of_sets_in_the_stadium 太短: n,nsisd 正好: num_sets_in_stadium
1.4)變量名中的限定詞
很多程序都有表示計(jì)算結(jié)果的變量:總額、平均值、最大值等等,如果要用類似total、sum、average、max、min、record、string、pointer這樣的限定詞來(lái)修飾某個(gè)事物,請(qǐng)把限定詞放到名字的最后。
因?yàn)樽兞棵凶钪匾?,即為這一變量賦予主要含義的部分應(yīng)當(dāng)位于最前面,這樣這一部分就可以顯得最為突出,又可以首先被閱讀到。另外將限定詞統(tǒng)一放在后面可以提高可讀性,簡(jiǎn)化維護(hù)工作。
2)為特定類型的數(shù)據(jù)命名
2.1)為循環(huán)下標(biāo)命名
循環(huán)我們基本上天天用,小到寫(xiě)個(gè) shell 腳本,大到登月工程,在軟件工程中很常見(jiàn)。
既然經(jīng)常那么 i、j、k 這些想來(lái)你也不陌生。如果一個(gè)變量要在循環(huán)之外用,那么就應(yīng)該為它取一個(gè)比i、j 或者 k 更有意義的名字。
如果循環(huán)不是簡(jiǎn)單幾行,閱讀代碼的人很容易就忘記本來(lái)的含義。
fruits = ['banana','apple','mango']for fruit in fruits: ? print(f"當(dāng)前水果:{fruit}")
為循環(huán)下標(biāo)變量命名可以避免下標(biāo)串話,就是想寫(xiě)j的時(shí)候?qū)懥薸,筆者本人之前寫(xiě)循環(huán)的時(shí)候就串話了,導(dǎo)致那個(gè)bug上了調(diào)試才定位找出來(lái)。
當(dāng)然i、j、k這三個(gè)循環(huán)下標(biāo)從c語(yǔ)言開(kāi)始就伴隨著我們,深入人心,所以想要用的時(shí)候盡量避免用于非下標(biāo)情況,給人造成誤解(想個(gè)更具有描述性的名字這事不就解決了)。
2.2)為狀態(tài)變量命名
狀態(tài)變量主要為了描述你的程序的狀態(tài)。
建議把標(biāo)記也看作狀態(tài)變量的一種,起一個(gè)比 flag 、status 更好的名字,標(biāo)記的名字不應(yīng)該包含 flag ,因?yàn)槟憧床怀鲈摌?biāo)記是做什么的。為了清楚起見(jiàn)我們還應(yīng)該用枚舉類型、具名常量或者用作居民常量的全局變量來(lái)進(jìn)行賦值。
2.3)為臨時(shí)變量命名
臨時(shí)變量用于存儲(chǔ)計(jì)算的中間結(jié)果。
我們經(jīng)常把它們寫(xiě)成temp、x或者其他一些模糊且缺乏描述性的名字(有沒(méi)有躺槍…)。
臨時(shí)變量是一個(gè)信號(hào),表明你還沒(méi)有完全把問(wèn)題理解清楚。而且,因?yàn)槲覀儗⑦@些變量“正式”的賦予了一種“臨時(shí)”狀態(tài),我們就會(huì)往往更加隨意的對(duì)待它,當(dāng)你忽略它,那么就有出錯(cuò)的可能了。
臨時(shí)性的保留一些值常常是有必要的,但是確實(shí)不管從哪個(gè)角度看,你程序中的大多數(shù)變量都是臨時(shí)的,把其中個(gè)別的稱為臨時(shí)性,說(shuō)明你還沒(méi)有弄清楚它們的實(shí)際用途。
2.4)為布爾變量命名
推薦一些經(jīng)典的布爾變量名
done: ? 用來(lái)表示某件事已經(jīng)完成。完成前 False ,完成后為 True 。 ?
error: ? 用來(lái)表示有錯(cuò)誤發(fā)生。錯(cuò)誤發(fā)生前 False ,發(fā)生時(shí)設(shè)置為 True 。 ?
found: ? 用來(lái)表示某個(gè)值已經(jīng)找到。沒(méi)找到前 False ,找到后為 True 。 ?
success 或者 ok: ? 用來(lái)表示某項(xiàng)操作是否成功。操作失敗 False ,操作成功為 True 。
給布爾變量賦予隱含“真假”含義的名字
像done和found就是不錯(cuò)的布爾變量名,因?yàn)槠錉顟B(tài)要么是 True ,要么是 False ,但是像 status 確實(shí)很糟糕的布爾變量值,因?yàn)樗鼪](méi)有明確的True和False。status是True表示啥?
還有程序員喜歡在他們寫(xiě)的布爾變量名前加上is(有沒(méi)有躺槍-_-|)。加上了is后,變量名就變成了is_error?is_complete??jī)?yōu)點(diǎn)之一就是不會(huì)用于不隱含“真假含義”的名字了,如is_status,缺點(diǎn)就是降低可讀性,比如if(is_found)可讀性略差于if(found)。
使用肯定的布爾變量名
比如not_found,not_done這樣看起來(lái)就比較難讀了,來(lái)個(gè)語(yǔ)句你感受一下。 ? if not not_found ? 玩門(mén)薩測(cè)試呢?這樣的名字就應(yīng)該替換為 found 之類的。
2.5)為具名常量命名
因?yàn)榫呙A亢芟褡兞?,所以放在這里說(shuō)一下。在為具名變量命名的時(shí)候,應(yīng)該依據(jù)常量代表的含義命名,而不是該常量所代表的數(shù)值。
3)應(yīng)該避免的名字
避免使用令人誤解的名字或者縮寫(xiě)
要確保名字的含義是正確的,大家知道 ATM 機(jī)是取錢的,但是網(wǎng)絡(luò)中有 Asynchronous Transfer Mode(ATM)異步傳輸模式,這種容易引起誤解的盡量避免。
3.1)避免使用具有相似含義的名字
如果兩個(gè)變量的名字交換而不影響你對(duì)程序的理解,那么你就需要為這兩個(gè)變量重新改名字了,因?yàn)槿绻迷谕欢未a里面很容易混淆,出現(xiàn)一下子不好發(fā)現(xiàn)的錯(cuò)誤。
避免使用具有不同含義但卻有相似名字的變量
如果含義不同卻名字相似的也要避免,比如client_recs和client_reps。這樣的名字只差一個(gè)字母,再加上編輯器補(bǔ)全時(shí)候很容易忽視,導(dǎo)致出現(xiàn)錯(cuò)誤。
3.2)避免使用發(fā)音相近的名字
使用發(fā)音相近的詞作為變量,主要有兩個(gè)不合適點(diǎn): ? - 第一個(gè)就是跟人討論時(shí)候,容易誤解。 ? - 第二做語(yǔ)音類測(cè)試時(shí)候。
3.3)避免在名字中使用數(shù)字
如果名字中的數(shù)字真的很重要,建議使用數(shù)組代替一組單個(gè)的變量。如果數(shù)組不合適,那么數(shù)字就更不合適了。要避免 file1 和 file2 , total1 和 total2 這種變量,過(guò)一段時(shí)間誰(shuí)也不知道它們是啥,你總可以想出不加數(shù)字就能區(qū)分變量的名字吧。特殊情況要特殊對(duì)待,比如深圳去上海的 G205 國(guó)道,美國(guó)的51 區(qū),建議再創(chuàng)建一個(gè)含有數(shù)字名字之前,請(qǐng)確定沒(méi)有更好的選項(xiàng)。
3.4)避免在名字中拼錯(cuò)單詞
本來(lái)別人看你代碼就要花點(diǎn)腦細(xì)胞,結(jié)果你拼錯(cuò)了。 content 和 context highlite 和 hilite 大哥們,饒了看你代碼的人吧。
3.5)避免僅靠大小寫(xiě)來(lái)區(qū)分變量名
所以語(yǔ)言區(qū)分大小寫(xiě),但還是避免僅靠大小寫(xiě)區(qū)分變量,大寫(xiě)名字和小寫(xiě)名字字面意思一樣,還是不要做不同的變量了吧。
3.6)避免使用標(biāo)準(zhǔn)類型,變量和函數(shù)的名字
不要用語(yǔ)言的關(guān)鍵字。很多語(yǔ)言現(xiàn)在不能寫(xiě)關(guān)鍵字,但是大小寫(xiě)不區(qū)分,比如python代碼:
>>> if = 1 ?File "",?
line 1 ? ?
if = 1
? ? ? ??^
SyntaxError: invalid syntax>>> If = 1>>>
本文提供了這么多變量名的方法就不要用關(guān)鍵字這種了。
3.7)避免使用與變量含義完全無(wú)關(guān)的名字

就問(wèn)你怕不怕?還有的喜歡給變量起一些對(duì)自己特殊意義的名字作為變量名,除非程序真的跟你特殊意義有關(guān)。這些能避免避免吧。
3.8)避免在名字中包含容易混淆的字符
把下列不屬于該組的名字圈出來(lái):
eye_Chart1 ?ttl5 ?TTLCONFUSION
eye_ChartI ?ttlS ?TTLCONFUSION
eye_Chart1 ?tt1S ?TTLC0NFUSION
還是不要搞這些找不同游戲才能出現(xiàn)的變量哈。
函數(shù)命名
1. 描述函數(shù)所做的所有事情
函數(shù)的命名應(yīng)該是動(dòng)詞或者動(dòng)詞短語(yǔ),如delete_page或save等。
函數(shù)的名字應(yīng)該描述其所有的輸出結(jié)果以及副作用,比如你的函數(shù)是計(jì)算報(bào)表總額并打開(kāi)一個(gè)輸出文件,那么把它命名為 computer_report_totals() 不能算完整。完整的應(yīng)該是 computer_report_totals_and_open_output_file() 。
如果寫(xiě)一些帶有副作用的子程序,那么就會(huì)起出上面那種長(zhǎng)出天際的名字,解決這個(gè)問(wèn)題的辦法不是使用描述性較弱的 computer_report_totals() 命名方式,而是換一種編寫(xiě)方式,直接了當(dāng)?shù)貙?xiě)成解決問(wèn)題,不產(chǎn)生副作用。
2. 給函數(shù)命名時(shí)要對(duì)返回值有所描述
函數(shù)有返回值,因此,函數(shù)的命名要應(yīng)該針對(duì)其返回值進(jìn)行。比如說(shuō) xxx_is_ready 這樣的,一看就讓人知道是返回的布爾值。
3. 準(zhǔn)確使用對(duì)仗詞
命名時(shí)遵守對(duì)仗詞的命名規(guī)則有助于保持一致性,從而提高可讀性。像 first/last,這樣的對(duì)仗詞就很容易理解,而像 file_open() 和 l_close() 就很讓人迷惑了,下面列出一些常見(jiàn)的對(duì)仗詞組。
add/remove
increment/decrement
open/close
begin/end
insert/delete
show/hide
create/destroy
lock/unlock
source/target
first/last
min/max
start/stop
get/put
next/previous
up/down
get/set
old/new
4. 函數(shù)名字長(zhǎng)度
研究表明,變量名的最佳長(zhǎng)度是9到15個(gè)字符,在面向?qū)ο蟮恼Z(yǔ)言中,函數(shù)是跟在對(duì)象的名字之后,這實(shí)際上是為其提供了一部分的名字。重點(diǎn)的盡可能的含義清晰,長(zhǎng)短要視名字是否清晰而定。
5. 為常用操作確立命名規(guī)則
在某些系統(tǒng)里,區(qū)分不同類別非常重要,而命名規(guī)則往往能是指示這種區(qū)別的最簡(jiǎn)單也是最可靠的辦法。忽視了為返回對(duì)象標(biāo)識(shí)的類函數(shù)建立一個(gè)命名規(guī)則,看看下面的名字 ? - employee.id.get()?
dependent.get_id()?
candidate.get_id()
6. 類命名
類的命名應(yīng)該是名詞或者名詞短語(yǔ),如 Customer 或者 AddressParser。
命名工具推薦
Codelf 由前網(wǎng)易前端工程師知名移動(dòng)前端調(diào)試工具 MIHTool 的作者基于searchcode 和有道詞典開(kāi)發(fā)完成。目前開(kāi)源在 Github上。
Codelf:http://unbug.github.io/codelf/
Codelf 的 github repo:https://github.com/unbug/codelf
文學(xué)系的可以搜搜熱詞:盤(pán)它

我太南了

總結(jié)
白居易每作一首詩(shī),都要給不識(shí)字的老太太念念,老太太能聽(tīng)懂的,就要,聽(tīng)不大懂的,就改。我們的代碼命名是我們寫(xiě)成好代碼的基礎(chǔ),也應(yīng)該奔著這個(gè)目標(biāo)走。大家看文章過(guò)程中覺(jué)得有不妥的或者不合適的地方,歡迎討論交流哈。
參考書(shū)籍
《代碼大全2》:https://book.douban.com/subject/1477390/
《代碼整潔之道》:https://book.douban.com/subject/4199741/
《重構(gòu)》:https://book.douban.com/subject/30468597/
轉(zhuǎn)自:于顏川KM分享
更多后臺(tái)和前端開(kāi)發(fā)規(guī)范
藍(lán)鯨文檔中心開(kāi)發(fā)指南:https://bk.tencent.com/docs/document/6.0/130/5871
Python代碼規(guī)范小結(jié):https://bk.tencent.com/s-mart/community/question/1078
藍(lán)鯨智云
本文由騰訊藍(lán)鯨智云編輯發(fā)布,騰訊藍(lán)鯨智云(簡(jiǎn)稱藍(lán)鯨)軟件體系是一套基于PaaS的技術(shù)解決方案,致力于打造行業(yè)領(lǐng)先的一站式自動(dòng)化運(yùn)維平臺(tái)。目前已經(jīng)推出社區(qū)版、企業(yè)版,歡迎體驗(yàn)。
- 官網(wǎng):https://bk.tencent.com/
- 下載鏈接:https://bk.tencent.com/download/
- 社區(qū):https://bk.tencent.com/s-mart/community/question