編碼之道:取個好名字很重要
代碼就是程序員的孩子,給“孩子”取個好聽的名字很重要!
我們在項目開發(fā)中,接觸到的變量、函數(shù)、類多數(shù)都是項目自己定義的,往往都是為了解決一些特定的領域的問題,引入了各種各樣的概念,代碼里面的名字 就對應著問題領域或方案領域的這些概念,所以,對于一個命名良好,代碼規(guī)范,設計簡潔的系統(tǒng),要想非??斓睦斫庖粋€系統(tǒng),最直接的方式就是 RTFC(Read The Fucking Code)。對于一個不斷演進的系統(tǒng),代碼的可讀性至關重要,首要要解決的問題就是名字,變量名、函數(shù)名、類名等都需要仔細斟酌,認真對待,一個能夠簡 潔,能夠清晰表達概念和意圖的名字就顯得尤為重要。
閱讀《代碼整潔之道》這本書后發(fā)現(xiàn)其中說的內(nèi)容在我們自己項目中比比皆是,隨便拿出一塊代碼都可以當做反面教材給大家講半天。長時間積累,導致代碼 發(fā)霉變質(zhì),取名也是毫無章法,信手拈來。閱讀這樣的代碼,撞南墻的心都有了。下面結(jié)合自己項目中的問題和《代碼整潔之道》談談關于命名相關的原則。
1. 原則:名副其實
-
選名字是件嚴肅的事情,選個好名字很重要。
-
如果名字需要注釋來補充,那就不是個好名字。
-
最重要的是要名副其實,名字能表達出概念和意圖。
BAD:
int t = currentTime.elapse(e); // 消逝的時間,以毫秒計
...
if (t > timeout_value)
{
Zebra::logger->debug("---一次循環(huán)用時 %u 毫秒-----", t);
}
GOOD:
int elapsed_ms = currentTime.elapse(e);
...
if (elapsed_ms > timeout_value)
{
Zebra::logger->debug("-----一次循環(huán)用時 %u 毫秒---", elapsed_ms);
}
2. 原則:避免誤導
-
必須避免留下掩藏代碼本意的錯誤線索
-
避免使用與本意相悖的詞
-
提防使用不同之處較小的名稱
-
拼寫前后不一致就是誤導
BAD:
std::vector<int> account_list; // _list就是一個誤導, accounts會更好
bool sendToZoneServer(); // 和下面的函數(shù)差別很小
bool sendToZoneServers(); // sendToAllZoneServers會好點
3. 原則:做有意義的區(qū)分
-
代碼是寫給人看的,僅僅是滿足編譯器的要求,就會引起混亂
-
以數(shù)字系列命名(a1,a2,…),純屬誤導
-
無意義的廢話: a, an, the, Info, Data
BAD:
void copy(char a1[], char a2[]) {
for (size_t i = 0; a1[i] != '/0'; i++)
a2[i] = a1[i];
}
GOOD:
void copy(char source[], char dest[]) {
for (size_t i = 0; source[i] != '/0'; i++)
dest[i] = source[i];
}
4. 原則:使用可讀的名字
-
避免過度使用縮寫
-
可讀的名字交流方便
猜一猜下面的類是干什么的?和別人怎么說這幾個類?
根據(jù)這些簡直變態(tài)的縮寫,如果沒有注釋基本上很難知道是干什么的,當你和別人交流的時候,你就不得不一個一個字母來念“X-L-Q-Y”、“L- T-Q Manager”,鬼知道你說的是什么?PS. XLQY-XianLvQiYuan(仙履奇緣), LTQ-LiaoTianQun(聊天群),有這樣的名字也是醉了。
BAD:
class XLQY;
class FCNV;
class LTQManager;
5. 原則:使用可搜索的名字
-
避免使用Magic Number
-
避免使用單字母,或出現(xiàn)頻率極高的短字母組合(注意度的把握)
BAD:
if (obj->base->id == 4661) // 4661是啥玩意?
{
usetype = Cmd::XXXXXXX;
}
int e; // 怎么查找?
XXXX:iterator it; // 變量作用的范圍比較大的時候,也不見得是個好名字
GOOD:
#define OJBECT_FEEDBACK_CARD 4661
if (OJBECT_FEEDBACK_CARD == obj->base->id)
{
usetype = Cmd::XXXXXXX;
}
6. 原則:避免使用編碼
-
匈牙利標記法:
-
Windows API時代留下的玩意
-
形如:wdXX, dwXXX, strXXX
-
類型變換導致名不副實,就有可能出現(xiàn)明明是個DWORD,變量名卻是qwNum。
-
PS.匈牙利命名對于我們這些在Linux下摸爬滾打的好多年的來說,看著真心別扭。
-
成員前綴:
-
形如:m_name, m_xxx
-
基本上都無視,為何要多次一舉
-
PS.說到這一點,可能有些同學有不同意見了,“我這樣寫是為了區(qū)分成員變量和臨時變量?。?rdquo;,好像這樣寫也沒什么大不了,遵循代碼規(guī)范即可。如 Google的C++代碼規(guī)范,私有變量形如:xxx_,加后綴_,其目的除了讓你知道這貨是個私有變量,還有一點就是防止有些人圖省事把帶私有變量直接 public掉,因為誰也不喜歡在代碼里面看到大量這些帶把的玩意。
-
接口和實現(xiàn):
-
接口名形如:IXXX, I-接口修飾前綴
-
類名形如:CXXX, C-類修飾前綴
-
這些修飾多數(shù)時候都是廢話
-
7. 原則:名字盡量來自解決方案領域或問題領域
-
使用解決方案領域名稱:
寫代碼的同學多數(shù)都是都出自CS,術語、算法名、模式名、數(shù)學術語盡管用。如AccountVisitor:Visitor模式實現(xiàn)的Account類。
-
使用問題領域的名稱
我們代碼里面多數(shù)都是這些名稱,不明白找策劃問問,基本上都是功能相關的名稱。
8. 原則:適當使用有意義的語境
-
良好命名的類、函數(shù)、名稱空間來放置名稱,給讀者提供語境
-
只有兩三個變量,給名稱前加前綴
-
事不過三,變量超過三個考慮封裝成概念,添加struct或class
BAD:
// 看著整齊?使用方便?
DWORD love_ensure_type_; //當前的愛情保險類型
DWORD love_ensure_ret_; //購買愛情保險回應標示
DWORD love_ensure_total_; //現(xiàn)在已經(jīng)蓋章數(shù)目
DWORD love_ensure_..._; //...
DWORD love_ensure_..._; //...
最后:我們的C++命名規(guī)范
-
文件名:
-
首字母大寫,多個詞組合起來
-
如: SceneUser.h Sept.h
-
-
類名/名稱空間名:
-
首字母大寫,多個詞組合起來
-
使用名詞或名詞詞組
-
避免使用C前綴,如:CSept
-
如: SceneUser SeptWar
-
-
函數(shù)名:
-
首字母小寫
-
使用動詞或動詞詞組
-
避免使用孤立的全局函數(shù),可以封裝在類或名稱空間里面
-
get, set, is前綴的使用
-
如: fuckYou(), levelup()
-
-
變量名:
-
全部字母小寫,多個詞以下劃線分隔
-
私有成員變量加后綴_,公有變量不用
-
避免使用孤立的全局變量,可以封裝在類或名稱空間里面
-
如: quest_id, questid_
-
取名是一件嚴肅的事情,我們需要認真對待,名字代表著一個個概念,名字代表著你想表達的意圖,好名字是可讀代碼的首要條件:
-
寫下任何一行代碼的時候,心里都要想著自己的代碼是給別人看的。
-
為函數(shù)、變量、類取個好名字,遵循規(guī)范和原則。
-
見到不符合規(guī)范和原則的名字,確毫不留情的干掉它,特別是功能性的代碼。