天天看點

《Clean Code》讀書筆記函數第四章注釋

翻網站想買書的時候看到了這本書,毅然決然的買了。那時候我正要準備寫我畢業設計的程式。

這本書提到了很多關于程式設計上需要注意的點,覺得有些地方很有用是以想整理出來供大家參考也友善我以後複習。

書中講了很多程式設計上注意的細節。不過這些細節還是需要自己長期代碼的積累,如果目前還沒有自己的代碼風格,那可以依照這本書的建議多加練習積累。但是如果自己已經有一套代碼風格,那也沒有必要非要跟着作者的那一套來。盡信書不如無書... 

下面是我的整理的内容

第二章 命名

名副其實

好的命名應該告訴你,它為什麼會存在,它做什麼是,應該怎麼用。如果命名需要注釋來補充,那就不是名副其實。

注意命名,而且一旦發現有更好的名稱,就換掉舊的

例如:

Int d; // 消逝的時間,以日計
           

改為

Int elapsedTimeInDays;
           

做有意義的區分

廢話都是備援的。Variable 一詞永遠不應當出現在變量名中。Table一詞永遠不應當出現在表名中。NameString會比Name 好嘛?難道Name會是個浮點數不成?

缺少明确的規定,變量moneyAmount 就和money沒差別,customerInfo與customer沒差別,accountData與account沒差別,theMessage也與message沒差別。 要區分名稱,就要以讀者能鑒别不停之處的方式來區分。

這部分是我嘗嘗不注意的地方,很容易把命名搞的冗長。

使用讀的出來的名稱

作者舉了下面這個例子

變量名為 genymdhms(生成日期,年月日時分秒)

改成下面這個可能更加易于了解

generationTimestamp

類名: 名詞或者名詞短語

方法名: 動詞或者動詞短語

每個概念對應一個詞,并且一以貫之

如 fetch、retrieve、get來給多個類種的同種方法命名

使用解決方案領域名稱

因為隻有程式員才會讀你的代碼,是以盡管使用術語、算法名、模式名、數學術語。

使用源自所涉及問題領域的名稱,這樣負責維護代碼的程式員就能請教專家了

添加有意義的語境

假設有firstName、lastName、street、houseNumber、city、state、和zipcode的變量。當它們在一塊的時候,很明确的構成了一個位址,但是假使隻是在某個方法中看見的孤零零一個state變量時,你就可能不知道是什麼資訊了。是以這裡可以添加一個字首addrFirstName、addrLastName、addrState等。當然最好是建立名為Address的類。

------

函數

3.1 短小

函數的第一規則是要短小,第二條規則是還要更短小。

每行最多不能超過150位元組

函數也不應該有100行那麼長,20行封頂最好。

代碼塊和縮進

If 、else、while等語句其中的代碼塊應該隻有一行,該行大抵應該是一個函數調用語句。這樣不但能保持函數短小,而且,因為快内調用的函數擁有較具說明性的名稱,進而增加了文檔上的價值。

這也意味着函數不應該大到足以容納嵌套結構。是以函數的縮進層級不應該多于一層或兩層。當然,這樣的函數易于閱讀和了解。

3.2 隻做一件事

函數應該隻做一件事。做好這件事。隻做好這一件事。

3.3 每個函數一個抽象層級

自頂向下讀代碼:向下規則

3.5 使用描述性的名稱

長而具有描述性的名稱,要比短而令人費解的名稱好。

長而具有描述性的名稱,要比描述性的長注釋好。

命名方式要保持一緻。使用與子產品名一脈相承的短語、名詞和動詞給函數命名。

3.6函數的參數

最理想的參數數量是零(零參數函數)其次是雙參數函數,盡量避免三參數函數,有足夠特殊的裡有才能用三個以上的參數(多參數函數)

參數對象:如果函數需要兩個、三個及三個以上的參數時,就說明其中一些參數應該封裝成類了。

如:

Circle makeCircle (double x, double y, double radius);

Circle makeCircle (Point center, double radius);

3.6.7 函數與關鍵字

對于原函數和參數應當形成非常好的動詞/名詞對形式

write(name) 已經足夠讓人能夠了解了,不過更好的是writeField(name)它告訴我們name是一個 field

assertEqual改成assertExpecedEqualsActual(expected,actual)就會好一些,這大大減輕了記憶參數順序的負擔

3.8 分隔指令與詢問

函數要麼做什麼事,要麼回答什麼事,二者不可兼得。函數應該修改某對象的狀态,或是傳回該對象的有關資訊。兩樣都幹常會導緻輪亂。

如: public boolean set(String attribute, String value)

 if(set("username","unclebob"))…

由于傳回是布爾值容易引起歧義 不明确是判斷是否存在還是判斷是否set 成功。

作者本意,set是個動詞,但是在if的上下文中,感覺他是個形容詞。

解決方案吧指令與詢問分割開來,防止混淆

If(attributeExists("username")){

setAttribute("username","unclebob")

}

3.9

抽離try/catch 代碼塊

try{

    deletepage(page);

    registry.deleteReference(page.name);

    configKeys.deleteKey(page.name.makeKey());

}

catch (Exception e){

    Logger.log(e.getMessage())

}
           

Try/catch代碼搞亂了代碼結構,把錯誤處理與正常流程混為一談,最好把try和catch 代碼塊的主體部分抽離出來,另外形成函數。

public void delete(Page page){
		try{
			DeletePageAndAllReferences(page);
		}
		catch (Exception e){
			logError(e)
		}
	}
	
	private void deletePageAndAllReferences(Page page) throws Exception{
		deletepage(page);
		registry.deleteReference(page.name);
		configKeys.deleteKey(page.name.makeKey());
	}
	private void logError(Exception e){
		Logger.log(e.getMessage())
    }
           

函數是語言的動詞,類是名詞。大師級的程式員把系統當成故事來講。

第四章注釋

注釋的恰當用法是彌補我們在用代碼表達意圖時遭遇的失敗。注釋是一種失敗。我們總無法找到不用注釋就能表達自我的方法,是以用藥有注釋,這并不值得慶賀。

因為注釋容易撒謊,程式員不能堅持維護注釋,是以在代碼改變的情況中,注釋沒有随之變動,不能總是跟着走。是以隻有代碼才是唯一真正準确的資訊來源。監管有時也需要注釋,我們也應該多花些心思盡量減少注釋量。

好注釋

法律資訊,例如版權著作權聲明 如// Copyright © XXXX

提供資訊的注釋

// return an instance of the Responder being tested

Protected abstract Responder responderInstance()
           

對意圖的解釋

闡釋:把晦澀難懂的參數或者傳回值的意義解釋成某種刻度的形式

assertTure(a.compareTo(a) == 0 ) // a==a

assertTure(a.compareTo(b) != 0 ) // a!=b
           

警示:用于警告其他程式員會出現某種後果的注釋

// don’t run unlesss you have some tome to kill

Xxxxxx  your code
           

TODO 注釋:程式員認為應該做,但是由于某些原因還沒做的工作

放大:注釋可以放大某種看起來不合理之物的重要性

壞注釋

這部分就略過了主要記住什麼時候值得寫注釋就好。

第五章 格式

空白行分開概念

有聯系的藥緊湊

變量聲明盡可能靠近使用位置

循環中變量聲明在循環中。for(int i = 0 ; i<10; i++)

實體變量在類的頂部聲明

某個函數調用了另一個,把它們放在一起,調用者在被調用者上面

概念相關的代碼在一起

橫向不超過120字元

空格分隔 如 return b*b  -  4*a*c 就比 return b*b-4*a*c 讀起來更舒服

用同一種風格程式設計: 同一個團隊使用團隊約定的程式設計風格

繼續閱讀