??注釋是代碼中很重要的提示,當(dāng)你在閱讀別人的或者自己以前寫過的代碼時往往能夠起到一個“指點(diǎn)迷津”的作用。這篇讀書筆記將內(nèi)容劃分為三個部分:
Part 1:哪些情況不需要注釋
Part 2:哪些情況需要注釋
Part 3:怎么寫出言簡意賅的好注釋
<h3>Part 1:哪些情況不需要注釋</h3>
-
不要為那些從代碼本身就能快速推斷的事實(shí)寫注釋
Q:為什么說有的時候沒有注釋比有注釋更好?
A:這個問題可以用文中的一段開場白來回答。
閱讀注釋會占用閱讀真實(shí)代碼的時間,并且每條注釋都會占用屏幕上的空間。那么,它最好是物有所值的。
下面拋出一段“壞味道”的注釋,感受一下:
//The class definition for Account
public Account{
//Construtor
Account();
//set the profit member to a new value
void setProfit(double profit);
//return the profit from this Account
double getProfit();
}
從這段“壞掉”的注釋中可以看出來,它所附帶的信息對于是毫無價值的,況且代碼量又不能用來衡量KPI,所以絕對杜絕寫這種注釋。
-
不要為不好名字寫注釋
想要寫出“可讀”的代碼,那么為常量、變量、函數(shù)起一個好的名字就是第一步(怎么寫?以后我將補(bǔ)上,本文只討論注釋)。但是很多時候我們“懶得”去想一個好的名稱而不得不補(bǔ)上一堆解釋作用的注釋。一個好的名字不一個好的注釋更重要,注釋只會出現(xiàn)多次,而函數(shù)或變量卻會出現(xiàn)多次。
<h3>Part 2:哪些情況需要注釋</h3>
??很多好的注釋僅通過“記錄你的想法”就能得到,也就是那些你在寫代碼時的重要想法。從寫代碼的角度來看,以下幾種情況需要注釋。
- ** 加入“導(dǎo)演評論”**
Q:什么是“導(dǎo)演評論”?
“導(dǎo)演評論”就是電影制作者在電影中給出自己的見解并通過講故事來幫助你理解這部電影是如何制作的。同樣,你應(yīng)該在代碼中也加入注釋來記錄你對代碼有價值的見解。
下面給出文中的例子:
//出乎意料的是,對于這些數(shù)據(jù)用二叉樹比用哈希表快40%
//哈希運(yùn)算的代價比左/右比較大得多
另一個例子:
//作為整體可能會丟掉幾個詞。這沒有問題。要100%解決太難了
當(dāng)然,注釋也可以用來解釋為什么代碼寫得不那么整潔(這可不是說鼓勵代碼寫得很隨意),或者是提醒繼任者是時候戴上重構(gòu)的帽子了:
//這個類正在變得越來越亂
//也許我們應(yīng)該建立一個‘ResourceNode’子類來幫助整理
-
代碼中存在瑕疵
當(dāng)代碼存在以下問題是,可以采用表中相應(yīng)的注釋:
| 標(biāo)記 | 意義 |
|---|---|
| TODO | 還沒處理的事 |
| FIXME | 已知的無法運(yùn)行的代碼 |
| HACK | 對一個問題不得不采用的比較粗糙的解決方案 |
| XXX | 危險!這里有重要的問題 |
給出一個例子:
// TODO 采用更快的算法
-
常量加注釋
當(dāng)定義常量時,通常在常量的背后都有一個關(guān)于它是什么或為什么它是這個值的故事。作為程序員,選擇這個某個值的原因往往是讀代碼的人不知道的,為了避免讀者可以去猜測,最好為常量值寫上注釋。
NUM_THREADS = 8; //設(shè)置為1太小了,設(shè)置成50又太夸張了
站在讀者的角度,以下幾種情況也是需要注釋的:
-
意料之中的提問
對于某些代碼,當(dāng)你意識到別人在讀的時候可能產(chǎn)生“為什么這樣”的疑問時,就要為這部分代碼加上注釋了。
//Force vector to relinquish its merory
vector<float>().swap(data);
-
公布可能的陷阱
當(dāng)你意識到代碼可能有什么出人意料的情況,也要附上注釋。
//運(yùn)行時間將達(dá)到0,所以小心嚴(yán)重嵌套的輸入
def FixBrokenHtml(html): …
-
“全局觀”注釋
當(dāng)團(tuán)隊(duì)有新成員加入時,具備“全局觀”的注釋將很快的讓能讀懂原來的代碼。給出一個例子:
//這個文件包含了一些輔助函數(shù),為我們的文件系統(tǒng)提供了更便利的接口
//它處理了文件權(quán)限以其他基本的細(xì)節(jié)
-
“總結(jié)性”注釋
“總結(jié)性”注釋和“全局觀”注釋有點(diǎn)相似,但它往往是一個類或函數(shù)內(nèi)部的,為多個函數(shù)或程序語句做一個總結(jié)。給出一個例子:
//數(shù)據(jù)庫連接參數(shù)
private String classname="com.mysql.jdbc.Driver";
private String dbConntctedURL = "*******";
private String user = "root";
private String password = "*******";
Part 3:怎么寫出言簡意賅的好注釋###
-
克服“作者心理阻滯”
Q:什么是“作者心理阻滯”?
A:簡單來說,就是程序員“懶得”去寫的那種“懶”(言簡意賅哈哈哈)。
想要克服“作者心理阻滯”,唯一的辦法就是寫。剛開始可以先寫下心中想的,然后逐漸的提煉,改進(jìn)。多次循環(huán)過后你就達(dá)到信手拈來的境界了。下面是書中提到具體操作的幾個要點(diǎn): - 聲明代碼的意圖
- 讓注釋保持緊湊
- 采用信息量高的詞
- 潤色粗糙的句子
-
避免使用不明確的代詞
例子:
//Insert the data into the cache, but check if it's too big fist
“it”所指究竟是data還是cache?如果改為下面的就好理解多了
//Insert the data into the cache, but check if the data too big fist
-
精確的描述函數(shù)的行為
假設(shè)你寫了一個函數(shù),它統(tǒng)計一個文件中的行數(shù):
//Return the number of lines in this file.
int CountLines(String filename);
上面的注釋并不是很精確,因?yàn)樗嬖谄缌x,或者說還有幾種特別的情況:
- “”(空文件)——0或1行?
- “hello”——0或1行?
- “hello\n”——1或2行?
- “hello\n world”——1或2行?
???但如果你寫的注釋是這樣的:
//Count how many newline bytes('\n') are in the file
int CountLines(String filename);
-
用輸入/輸出例子來說明特別的情況
對于注釋,有時候一個精心挑選的輸入/輸出例子比千言萬語還有效。
//Remove the suffix/prefix of 'chars' from the input 'src'
String Strip(String src, String chars)();
看了上面的注釋,問題來了:chars是整個要移除的子串,還是一組無序的字母?如果在src結(jié)尾有多個chars會怎么樣?顯然,精心挑選的例子就可以完美的回答問題:
//…
//Example:Strip("ab", "a") returns "/a/"
String Strip(String src, String chars)();