多年來,我非常榮幸能和一些謙遜的公司和客戶合作。我也因此有機會接觸到各種不同的程序員—— 每個程序員都有自己獨特的風格。事實上,每個項目本身都有一些獨特的元素。
這些特質的交叉讓我去思考我曾經審查、更新或提高過的程序代碼。與其說是代碼的實際邏輯,還不如說是開發人員自己添加到代碼中的注釋,對代碼產生了頗為深遠的影響。這篇文章的主題就是羅列一些我印象深刻的一些代碼注釋。
comment
我記得審查程序代碼時,有一條注釋是這樣寫的:
// Because Carol Told Me to Do This
在閱讀這行代碼時,我一下子就懵了,“誰是Carol?”以及“Carol讓這個開發人員做什麼了?”雖然寫代碼的程序員知道這兩個答案,但換做是一個局外人或者是一個後面加進來的人,那麼這條注釋就毫無價值。當我和我的經理說起這條注釋的時候,他哈哈大笑,只是說了句Carol明顯是一個人名字之後,就無下文了。好吧,直到現在,我依然不知道這句注釋究竟是什麼意思。
在另一種情況下,我相信我將問題范圍縮小到了一個特定的類。但是打開這個類,我看到大量的代碼被塊注釋掉了。讓人瘋狂的是,注釋的代碼是在方法的中間。所以,我只能在閱讀完頂部的代碼之後,滾動幾個屏幕,才能繼續閱讀剩下的代碼。你得牢記在心裡,幸好中間間隔的時間不是太久,有到應用程序的源代碼庫的鏈接。
在我心中,我對此非常嗤之以鼻,“提前閱讀沒有注釋的大塊代碼,卻只是看到了程序是用來做什麼的”。當我問另一名開發人員為什麼代碼要像這樣被注釋和檢查的時候,他給我的回答是“萬一我們下次還要用到它呢”。我真心無語。
在工作於一個基於web的應用程序時,我發現了以下的JavaScript注釋:
// make sure it's correctly formatted, because in javascript things
// like '7' or '4.3' or 'derpdy do 77' are valid dates
// seriously, try it out for yourself: Date.parse('derpdy do 77')
這裡的開發人員意識到Date.parse()方法存在著問題。為了警示他人,開發人員決定添加注釋作為警告,同時又苦中作樂了一番。我只能想象當這個開發人員意識到此路不通時心中該是有多麼的沮喪。
有些時候,程序員意識到他們的做法並不好。很多時候,這是基於開發小組之外所能做的唯一選擇。於是,出現了這樣的注釋:
// Sorry for what you are about to see
閱讀代碼和理解實施方法背後的情況有助於完整地理解簡單的道歉式注釋。這有點像驚悚片裡的英雄在采取有計劃的行動之前,先道歉的那一幕。
一開始作為一個白板聲明,最終被轉移到以下注釋:
// Doing this to "not do anything to effect Eric and Steve's code"
基本上,這是一個進程的入口點,代碼圍繞明顯由Eric和Steve引入的問題。但是我沒有任何相關的背景,也不認識Eric和Steve,我只知道任何影響了他們的代碼都得禁止。
我們都聽過這樣一句話:“好的代碼是自文檔化的”。我完全同意這種說法,當然有些注釋還是有必要的。但是,下面這種注釋,明顯不能劃到“必要”的范疇中:
returntrue;// returns true
這種注釋確明顯是沒有必要的,因為我們很容易理解返回什麼。我能想出的關於為什麼要這麼注釋的唯一原因就是,開發人員在添加到實際代碼前,使用注釋先制定出了方法,後來卻忘記刪掉這些注釋了。但是如果有代碼審查過程的話,就不會出現這樣的注釋。
還記得前面提過的“好的代碼是自文檔化的”這句話嗎?那麼,也許在所有注釋中,最糟糕的就是提供了錯誤信息的注釋。請看下面這個簡單的例子:
// Always returns false
public boolean isActive(){
returntrue;
}
現實中我所看到的例子遠遠沒有這麼簡單。然而更糟糕的是,當你需要依賴注釋寫一個復雜的方法時,才意識到這樣的注釋是無效的。在這種情況下沒有注釋都比錯誤的注釋好。
最後一種我見過的注釋是,開發人員寫的類似於小說般的注釋:
/**
* This is the widget method which will process the list of
* widgets from the widget controller and service in order to
* handle pre-processing (where the widget information is
* compared against the average widget history), actual
* processing (where the quarterly, monthly and week attributes
* are updated) and all of the post-processing (which include the
* analytical metrics and audit table updates) aspects. It is
* important to remember the widget rules around leap year where
* the cost to transfer rate is 75% adjusted to the annual rate in
* order to account for the extra day. When this happens, the
* process will throw the LeapYearException which will need to be
* validated by the application support staff. Failure to do so will
* end up causing issues with the ME-4110 report.
*/
我的經驗法則是,任何需要那麼多信息的代碼或許應該分解成更小的方法。而且注釋中這樣的信息應該挪到實際的代碼之外。而在上面的例子中,像流水賬一樣記錄的業務規則和業務流程——卻有可能隨著時間而改變。
關於如何正確地寫好代碼注釋,簡單地搜一下的話,網上有很多很多。有些甚至可能會告訴你如何盡可能地不在代碼中提供注釋。
相反,我想分享一些我有幸作為一個應用程序開發人員所讀過的一些滑稽的注釋。請記住,我在應用程序開發上有著20年以上的編譯經驗——反映了例外,而不是規則。
編碼快樂!