避免在程式碼裡寫註釋
如果用很多註釋來“裝飾”程式碼是件好事的話,那麼在程式碼中加入大片大片的註釋便是錦上添花了。是這樣嗎?事實上不完全是這樣的。過猶不及,好心也會辦壞事。
'*************************************************
' Name: CopyString
'
' Purpose: This routine copies a string from the source
' string (source) to the target string (target).
'
' Algorithm: It gets the length of "source" and then copies each
' character, one at a time, into "target". It uses
' the loop index as an array index into both "source"
' and "target" and increments the loop/array index
' after each character is copied.
'
' Inputs: input The string to be copied
'
' Outputs: output The string to receive the copy of "input"
'
' Interface Assumptions: None
'
' Modification History: None
'
' Author: Dwight K. Coder
' Date Created: 10/1/04
' Phone: (555) 222-2255
' SSN: 111-22-3333
' Eye Color: Green
' Maiden Name: None
' Blood Type: AB-
' Mother's Maiden Name: None
' Favorite Car: Pontiac Aztek
' Personalized License Plate: "Tek-ie"
'*************************************************
我常常不看開發者寫的註釋。似乎他們並不明白,其實他們的程式碼已經告訴了我它是怎樣工作的;我們需要註釋告訴我們的是,程式為什麼這樣工作。程式碼註釋已被廣泛地誤解和濫用,以致於你都開始懷疑它們原本的價值——註釋還有存在的必要嗎?你在期望什麼呢?要當心!這裡有一段完全沒有任何註釋的程式碼:
r = n / 2;while ( abs( r - (n/r) ) > t ) {
r = 0.5 * ( r + (n/r) );
}
System.out.println( "r = " + r );
明白這段程式碼想要做什麼嗎?它看起來一清二楚,但到底是幹什麼用的呢?
讓我們加上一行註釋:
// 用“牛頓-拉夫遜”近似法求解n的平方根
r = n / 2;
while ( abs( r - (n/r) ) > t ) {
r = 0.5 * ( r + (n/r) );
}
System.out.println( "r = " + r );
這個應該就是我想要的了。不是嗎?它介於完全沒有任何註釋與每隔一行就規規矩矩寫上史詩般的註釋這兩種極端之間,看似一個不錯的折中——你滿意了嗎?
未必!與其添加註釋,我更願意把這段程式碼重構成這樣:
private double SquareRootApproximation(n) {
r = n / 2;
while ( abs( r - (n/r) ) > t ) {
r = 0.5 * ( r + (n/r) );
}
return r;
}
System.out.println( "r = " + SquareRootApproximation(r) );
我一行註釋也沒有加,但這段神祕的程式碼現在已經非常容易理解了。
儘管註釋本身說不上好或者壞,它們卻常常被用作支撐程式碼的“柺杖”。你應該總是專注於編寫程式碼,而忘了還有註釋這種東西的存在。這會迫使你竭盡全力使用最簡單、最直白、最能自我說明的方式把程式碼寫出來。
為了讓你的程式設計師同伴們更易於閱讀和理解你的程式碼,如果你已經重寫、重構、甚至重新設計了很多遍——當你已經一籌莫展,已經想不出任何辦法可以讓你的程式碼變得更加淺顯易懂——這時候,也只有在這時候,你才應該迫不得已地加上些註釋來解釋你的程式碼是做什麼的。
就像Steve Yegge指出的那樣,這是初級開發者與高階開發者之間的一個關鍵差別:
坦率地說,要是在以前,讓我一下子看太多的程式碼會讓我崩潰,它的複雜度已經超越了我能接受的極限。而當我不得不在那些程式碼的基礎上繼續工作的時候,我通常會把它們重寫,或者至少也會寫上大量的註釋。現如今,當我碰到這種情況的時候我會披荊斬棘快速通過,而不會(過多地)抱怨。當我在腦子裡有了一個明確的目標、並且有一段複雜的程式碼要寫時,我會把時間花在程式碼實現上面,而不是(用註釋)寫下它的故事、講給我自己聽。
初級開發者依靠註釋來講故事,而實際上他們應該依靠程式碼本身。註釋是“旁白”,它們有其自身的價值,但絕不能用來替代(故事裡的)情節、人物和場景。
或許這才是關於程式碼註釋不可告人的小祕密:想要寫出好的註釋,你必須是一位優秀的作家。註釋跟程式碼不一樣,它不是給編譯器看的。註釋是用來和其他人類交流想法的文字。儘管我跟(大多數)程式設計師同伴們關係很好,但我必須承認,與其他人有效溝通真的不是我們的強項。我曾經收到過我們小組裡的一位程式設計師發來的電子郵件,裡面只有三段,但著實把我搞得暈頭轉向。我們能相信這樣的人會在程式碼裡寫出清晰、易懂的註釋嗎?於是我想,或許我們中的一些人去做那些我們擅長的事情會更好些——那就是,為編譯器寫程式碼,並且儘可能寫得清楚些,而只把註釋當作是最後沒有辦法的辦法。
寫出好的、有意義的註釋是很難的。就像寫程式碼一樣,它是一門藝術;或許還要更加藝術一點!就像Sammy Larbi在“Common Excuses Used To Comment Code and What To Do About Them”(註釋程式碼的常見藉口以及應對方法)一文中所說的那樣,如果你覺得你的程式碼在沒有註釋的情況下顯得過於複雜、很難被人理解,那隻能說明你的程式碼寫得很糟糕。重寫你的程式碼吧,直到它不再需要任何註釋。如果經過了這些努力,你仍然覺得註釋是必需的,那麼就盡你所能加上註釋吧。切記,小心!