我們都曾經瞟一眼自己親手造成的混亂,決定棄之不顧,走向新的一天。我們都曾經看到自己的爛程序居然能運行,然后斷言能運行的爛程序總比什么都沒有強,我們都曾經說過有朝一日再回頭清理。當然,在那些日子里。我們都沒有聽過布朗法則:later equals never 稍后等于永不.
看到這句話確實有點慚愧。印象最深的感覺就是,我們去看一兩年前自己的代碼,真的是自己都看不下去。要讓我改,我情愿再實現一個。所以時刻保持好的習慣是多么重要。不要想著以后再解決。就像領導說,這個事情以后再考慮,然后就沒有然后了
第一章 整潔代碼
怎樣是整潔的代碼?
代碼作品就像藝術品一樣,有不同的流派,在大師的眼里,對于優美與漂亮有不同的理解。關于什么是整潔代碼書中講述很多大師的觀點,各個側重點不同。
Bjarne Stroustrup 說:
“我喜歡優雅和高效的代碼,代碼邏輯應當直接了當,叫缺陷難以隱藏;盡量減少依賴關系,使之便于維護;依據某種分層戰略完善錯誤處理代碼;性能調至最優,省得引誘別人做沒有必要的優化,搞出一堆混亂來,整潔的代碼只做好一件事。”
Ron Jeffries 對整潔代碼的理解:
1.能通過所有的測試。
2.沒有重復代碼。
3.體現系統中的全部設計理念。
4.包含盡量少的實體、比如類、方法、函數等。
5.盡量少的依賴關系,便于維護。
6.整潔的代碼淺顯易懂,絕不故作高深;
“在以上諸項中,我最在意的是代碼重復。如果一段代碼重復出現,就表示某種想法未在代碼中得到良好的提現。我會盡力去找出到底那是什么,然后在盡力的更清晰的表達出來。”
總結下就是整潔的代碼:1.職責明確,沒有多余。2.減少依賴,便于維護。3.高效。
第二章? 有意義的命名
1.名副其實。 說起來很簡單。選個好名字需要花時間,但省下的時間比花掉的多。注意命名,一旦有好的命名,就換掉舊的。
int d;//消失的時間,以日計。int elapsedTimeInDays,int daysSinceCreation;
我們定義不同的變量,能夠看到名字就知道是什么意思,這是最基本的要求了。
2.避免誤導。比如不是List類型,就不要用個accountList來命名,這樣形成誤導。
3.做有意的區分。
Public static void copyChars(char a1[],char a2[]){
for(int i=0;i<a1.length;i++){
a2[i]=a1[i]
}
}
如果參數名稱改為source和destination ,這個函數就會像樣很多。廢話都是冗余的,Variable一詞?永遠不應當出現在變量名中。Table一詞永遠不應當出現在表名中。NameString 會比 Name好嗎,難道Name 會是一個浮點數不成?如有一個Customer的類,有又一個CustomerObject的類。是不是就凌亂了。
4.使用便于搜索的的名稱
單個字母或者數字常量是很難在一大堆文章中找出來。比如字母e,它是英文中最常用的字母。長名勝于短名稱,搜得到的名稱勝于自編的名稱。 竊以為單字母的名稱僅用于短方法中的本地變量。名稱長短應與其作用域大小相對應。
5.類名應該是名詞或短語
像Customer,Account,避免使用Manager,Processor,Data或者Info這樣的類名。類名不應當是動詞。方法名應該是動詞或動詞短語,如postPayment ,deletePage或Save,屬性訪問、修改和斷言應該根據其值來命名,并加上get,set,is這些前綴。
6.別扮可愛,耍寶
比如誰知道HolyHandGrenada 函數是干什么的,沒錯這個名字挺伶俐,但是不過DeleteItems或許是更好的名字。
7.每個概念對應一個詞。并且一以貫之。
在一堆代碼中有Controller,又有manager,driver。就會令人困惑。比如DeviceManager和Protal-Controller之間又什么本質區別?
第三章 函數
1.函數的第一規則是要短小,第二條規則是還要更短小。
2.函數應該做一件事。做好這件事。只做這一件事。
3.盡量少的函數參數。有兩個參數的函數要比一元函數的難懂。如果需要三個或者三個以上的參數應該封裝成類了。
4.不要重復自己。
如果一段相同的代碼出現了兩次,你是不是覺得自己改做些什么了。
第四章 注釋
注釋的恰當用法是彌補我們在用代碼表達意圖時遭遇的失敗。事實上注釋是一種失敗,我們總無法找到不用注釋就能表達自我的方法,所以總要有注釋,這并不值得慶賀。寫注釋的常見動機之一是糟糕代碼的存在。帶有少量注釋的整潔而有表達力的代碼,要比帶有大量注釋的零碎而復雜的代碼像樣的多。與其花時間編寫解釋你搞出的糟糕的代碼注釋,不如花時間清潔那堆糟糕的代碼。
好注釋:
1. 法律信息。有時,公司代碼規范要求編寫與法律有關的注釋。例如版權和著作申明。
2.提供信息的注釋。
//Returns an instance of the Responder being?
protected abstract Responder responderInstance();
不過將函數名重新命名為 responderBeingTested 注釋就是多余的。
3.對意圖的解釋。?有時注釋不僅提供了有關實現的有用信息,而且還提供了某個決定后面的意圖。
4.闡釋。 有時注釋把某種晦澀難明的參數或返回值的意義翻譯為某種可讀形式。也會是有用的。特別是參數或者返回值是某個標準庫的一部分,或者你不能修改代碼,那幫助闡釋其含義的代碼就會有用,例如:
assertTrue(bb.compareTo(ba)==1); // bb>aa?
assertTrue(a.compareTo(b)== -1); // a<b
直接看方法可能不明確,但有注釋就明白多了。
5.警示,告訴別人要注意這個方法之類的。
6.放大。有的代碼可能看著有點多余,但編碼者當時是有他自己的考慮,這個時候需要注釋下這個代碼的重要性。避免后面被優化掉。