代碼整潔之道

發(fā)布時(shí)間:2016-8-10 13:38    發(fā)布者:designapp
關(guān)鍵詞: 代碼
概述

1、本文檔的內容主要來(lái)源于書(shū)籍《代碼整潔之道》作者Robert C.Martin,屬于讀書(shū)筆記。

2、軟件質(zhì)量,不僅依賴(lài)于架構和項目管理,而且與代碼質(zhì)量緊密相關(guān),本書(shū)提出一種,代碼質(zhì)量與整潔成正比的觀(guān)點(diǎn),并給出了一系列行之有效的整潔代碼操作實(shí)踐,只要遵循這些規則,就可以編寫(xiě)出整潔的代碼,從而提升代碼質(zhì)量。

3、該書(shū)介紹的規則均來(lái)自于作者多年的實(shí)踐經(jīng)驗,涵蓋從命名到重構的多個(gè)編程方面,具有很好的學(xué)習和借鑒價(jià)值。

4、習藝要有二:知和行。你應當學(xué)習有關(guān)規則、模式和實(shí)踐的知識,窮盡應知之事,并且對其了如指掌,通過(guò)刻苦實(shí)踐掌握它!

前言


學(xué)習整潔代碼很難,它不止于要求你掌握原則和模式,你還得在上面下功夫,并自行實(shí)踐,體驗失敗。你須觀(guān)察他人如何實(shí)踐與失敗,怎樣蹣跚學(xué)步,再轉頭學(xué)習他們的路數,。

本書(shū)要求你多用信息,多用功,而且非常用功。如何用功?-大量閱讀代碼,并琢磨代碼好在什么地方,壞在什么地方。

本書(shū)大概分為三部分:原則、模式和實(shí)踐。

一、 使用有意義的命名


1、名副其實(shí)

注意命名,一旦發(fā)現有更好的名稱(chēng)就換掉舊的,這么做閱讀的人會(huì )更開(kāi)心

名稱(chēng)本身應該能解釋其含義,無(wú)需注釋就能看懂是最佳。比如

int d;//消失時(shí)間,以日計

int elapsedTimeInDays;

前者名稱(chēng)沒(méi)有任何含義,在程序中使用時(shí)看不出這個(gè)變量的實(shí)際作用,需要對應注釋才能看懂,因此遠不如后者的名稱(chēng)好!

2、避免誤導

程序員必須避免留下掩藏代碼本意的錯誤線(xiàn)索,避免使用與本意相悖的詞。

提防使用細節之處差別較小的名稱(chēng)

使用相同的拼寫(xiě)方式,前后拼寫(xiě)不一致(大小寫(xiě)不同),就是誤導。在使用編輯器名稱(chēng)自動(dòng)補全功能時(shí),拼寫(xiě)相近的變量容易引起誤選。

避免使用小寫(xiě)字母l和大寫(xiě)字母O作為變量名稱(chēng),易與1和0混淆

3、做有意義的區分

避免以數字系列命名,其無(wú)法提供正確的信息和導向作者意圖的線(xiàn)索。

不要使用意義相近的名稱(chēng),比如ProductInfo和ProductData變量不同,意思一樣,容易引起意義混淆

不要使用冗余信息,比如NameString,難道Name會(huì )是一個(gè)浮點(diǎn)數嗎?如果是,就不該使用Name命名。

4、使用讀的出來(lái)的名稱(chēng)

人類(lèi)善于記憶和使用單詞,如果名稱(chēng)無(wú)法閱讀或者發(fā)音,就不是一個(gè)好名稱(chēng),討論和交流時(shí)也難以表達。

比如函數名稱(chēng)為:genymdhms()//生成日期,年月日時(shí)分秒。

不要使用傻乎乎的自造詞,而要使用恰當的英語(yǔ)單詞

5、使用可搜索的名稱(chēng)

比如字母e,f等就不是一個(gè)好的變量名,其是英文常用字母,不方便搜索,

單字母名稱(chēng)僅限于本地局部變量使用,名稱(chēng)長(cháng)短應該與作用域大小相對應

如果程序中多出使用相同數字,實(shí)現相同功能,則需要使用宏定義變量代替。

比如WORK_DAYS_PER_WEEK就比數字5好搜索,也更能體現作者意圖

6、避免使用編碼

無(wú)需把類(lèi)型和作用域編進(jìn)名稱(chēng),這樣只會(huì )自找麻煩,既不便發(fā)音,也容易拼錯,對解決問(wèn)題毫無(wú)幫助。

匈牙利標記法,破壞了不編碼的規則,不應該采用。

也不必使用成員前綴,應該把類(lèi)和函數做的足夠小,同時(shí)使用可以高亮和顏色標出成員的編輯環(huán)境。(Keil,notepad++都支持)。

7、避免思維映射

不應當讓讀者把你腦中的名稱(chēng)翻譯成他們熟知的名稱(chēng),這個(gè)問(wèn)題常見(jiàn)于選擇使用問(wèn)題領(lǐng)域的術(shù)語(yǔ)還是解決方案領(lǐng)域的術(shù)語(yǔ)時(shí)。

在作為局部變量時(shí),并且名稱(chēng)沒(méi)有沖突時(shí),可以采用i,j,k作為循環(huán)變量。

專(zhuān)業(yè)程序員善用其能,編寫(xiě)能讓他人理解的代碼

8、類(lèi)名

類(lèi)名應該是名稱(chēng)或者名詞短語(yǔ),例如Customer、Account,避免使用Manager、Data、Info這樣的類(lèi)名,其不應該是動(dòng)詞。

9、方法名

方法名應該是動(dòng)詞或者動(dòng)詞短語(yǔ),比如postPayment、deletePage或s**e,屬性訪(fǎng)問(wèn)應該加上set、get、is前綴

10、每個(gè)概念對應一個(gè)詞

給每個(gè)抽象概念選用一個(gè)詞,并且一以貫之。比如使用fetch、retrieve、get在多個(gè)類(lèi)的中同種方法命名,就容易引起混淆。

11、別用雙關(guān)語(yǔ)

避免將以此用于不同目的,同一術(shù)語(yǔ)用于不同概念就是雙關(guān)語(yǔ)了。

比如多個(gè)類(lèi)中都有add方法,該方法通過(guò)增加或者鏈接兩個(gè)現存值來(lái)獲得新值,如果一個(gè)新類(lèi)的含義是,把單個(gè)參數放到群集(collection)中,使用add名稱(chēng),雖然保持了名稱(chēng)一致,你是含義卻不同,應該使用insert才對。

12、使用解決方案領(lǐng)域的名稱(chēng)

因為只有程序員才會(huì )讀取你的代碼,因此名稱(chēng)應該選擇解決方案領(lǐng)域的名稱(chēng),而不是問(wèn)題設計領(lǐng)域的名稱(chēng)。比如名稱(chēng)AccountVisitor就比JobQueue富有意義。

13、使用源自所涉及問(wèn)題領(lǐng)域的名稱(chēng)

當不能使用程序員所熟悉的術(shù)語(yǔ)命名時(shí),就應該采用所涉及問(wèn)題領(lǐng)域的名稱(chēng)

與所涉問(wèn)題領(lǐng)域更加貼近的代碼,應當采用源自問(wèn)題領(lǐng)域的名稱(chēng)

14、添加有意義的語(yǔ)境

很少有名稱(chēng)能夠自我說(shuō)明-多數都不能,因此需要使用良好命名的類(lèi)、函數來(lái)放置名稱(chēng),給讀者提供語(yǔ)境。

比如添加前綴addrFirstName、addrLastName、addrState,就可以提供語(yǔ)境,這些變量屬于地址范圍。更好的做法是,創(chuàng )建一個(gè)名稱(chēng)為Address的類(lèi),來(lái)存放這些相關(guān)變量。

語(yǔ)境的增強也讓算法能夠通過(guò)分解為更小的函數而變得干凈利索。

15、不要添加沒(méi)有意義的語(yǔ)境

比如應用(Gas Station Deluxe)簡(jiǎn)稱(chēng)為GSD,因此為每個(gè)函數、類(lèi)、變量增加同樣的前綴就GSD命名就不是一個(gè)好點(diǎn)子。

Address是個(gè)好名稱(chēng),但是如果需要與MAC地址、端口地址或Web地址區分,應當使用PostalAddress、MAC、URI,這樣的名稱(chēng)更為精確。

16、總結

取名字最難地方在于需要良好的描述技巧和共有的文化背景

試試上面的規則,看你的代碼的可讀性是否有所提升。如果維護別人的代碼,使用重構工具來(lái)解決問(wèn)題,效果也好立竿見(jiàn)影,而且會(huì )持續下去。
                                
                                                               
                                
               
二、關(guān)于函數的一些規則


1、短小

函數的第一規則就是短小。

代碼長(cháng)度以20行封頂為最佳。

if,else,while語(yǔ)句的代碼塊應該只有一行,這樣不但能保持函數短小,還能增加可讀性。

函數的層級不應該多于兩層,這樣才容易理解和閱讀。

2、只做一件事

函數應該只做一件事,做好這一件事。

判斷函數是否只做了一件事的方法就是看其是否能夠拆出一個(gè)函數,該函數不是單純的重新詮釋其實(shí)現。

3、每個(gè)函數一個(gè)抽象層級

要確保函數做做一件事情,函數中的語(yǔ)句都要在同一抽象層級上。這是保持函數短小的要訣。

4、函數參數

最好少于3個(gè),0個(gè)和1個(gè)最佳,3個(gè)以上請使用結構體代替。

輸出參數比輸入參數更加難以理解,讀函數時(shí),習慣于認為信息通過(guò)參數輸入函數,通過(guò)返回值輸出。

給函數起個(gè)好名字,使其能夠很好的解釋函數的意圖、以及參數的順序。比如assertExpectedEqualsActual(expected,actual)就容易理解和記憶。

5、無(wú)副作用

副作用指的是被其隱藏起來(lái)的事情,比如開(kāi)機檢查密碼函數,如果調用前密碼未經(jīng)初始化,就會(huì )出錯,就隱藏了其時(shí)序性耦合的要求。應該在其函數中增加初始化密碼的功能,盡管違反了只做一件事的。

6、分割指令與查詢(xún)

函數修改某對象的狀態(tài)或者獲取該對象的參數,應該分為兩個(gè)函數實(shí)現。

比如函數設置某個(gè)指定屬性,如果成功就返回true,失敗返回false,用例如下:

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

這樣的語(yǔ)句理解上面有歧義,set是動(dòng)詞,但是在上下文中感覺(jué)像形容詞,從讀者角度看,這句語(yǔ)句的意思是問(wèn)username的屬性是否已經(jīng)設置為unclebob?還是詢(xún)問(wèn)username的屬性是否成功設置為unclebob?因此最好改為如下所示:

if(attributeExists("username"))

{

setAttribute("username","unclebob");

}

7、使用異常代替返回錯誤值

直接返回錯誤代碼鼓勵了在if語(yǔ)句中把指令當做表達式使用,會(huì )導致多層次嵌套結構。如果返回異常代替錯誤碼,錯誤處理代碼就可以從主路徑代碼中分離出來(lái),得到簡(jiǎn)化

8、不要重復

重復的代碼可維護性差,如果算法修改,所涉及的地方都要更新,代碼臃腫,還會(huì )增加放過(guò)錯誤的可能!

如果一個(gè)算法在不同函數中重復出現,則需要使用一個(gè)獨立的函數修復它。

面向對象和面向組件編程也多多少少都是消除重復的策略。

9、結構化編程

只要保持函數短小,偶爾出現return、break、continue語(yǔ)句沒(méi)有什么壞處,甚至比單入單出更具表達力。

goto語(yǔ)句只在大函數中才能用到,因此盡量避免使用。

10、如何寫(xiě)出短小的函數

寫(xiě)代碼和寫(xiě)文章一樣,先寫(xiě)出初稿、再細細打磨,直至達到心中的樣子。

初寫(xiě)的函數,一般都是冗長(cháng)而復雜,有太多縮進(jìn)和嵌套循環(huán),名稱(chēng)隨意性大,代碼有重復。通過(guò)分解函數、修改名稱(chēng)、消除重復,然后遵循本章的規則,重新組裝函數,就可以寫(xiě)出短小精煉的函數。

三 關(guān)于注釋的規則


1、注釋不能美化糟糕的代碼

帶有少量注釋的整潔而有表達力的代碼,要比帶有大量注釋的零碎而復雜的代碼像樣的多!

與其花時(shí)間寫(xiě)注釋?zhuān)蝗缁〞r(shí)間清理早搞定糟糕的代碼。

代碼在變動(dòng)、演化,而很不幸,注釋不是總隨之變動(dòng),時(shí)間越久,注釋離代碼的本意就越久。只有代碼是唯一真正準確的信息來(lái)源。。

2、用代碼闡述

使用代碼本身解釋其行為。

比如//Check to see if the employee is eligible for full benefits

if((employee.flags &HOURLY_FLAG)&&(employee.age > 65))

通過(guò)創(chuàng )建與注釋所言同一事物的函數即可。

if(employee.isEligibleForFullBenefits())

3、好注釋

法律信息,比如公司代碼規范要求寫(xiě)的有關(guān)法律的注釋?zhuān)鏅嗦暶鞯取?br />
提供信息的注釋?zhuān)玫姆椒ㄊ鞘褂煤瘮得Q(chēng)傳達信息。

對意圖的解釋?zhuān)鹤⑨尣粌H提供了有關(guān)實(shí)現的有用信息,而且還提供了某個(gè)決定后面的意圖。

闡釋?zhuān)喊鸦逎y懂的參數或者返回值翻譯為可讀形式的注釋是有用的。

警示:用于警告其它程序員會(huì )出現某種后果的注釋也是有用的。

4、壞的注釋

喃喃自語(yǔ)式:只是覺(jué)得因為過(guò)程需要就增加的注釋。

多余的注釋?zhuān)罕旧聿⒉荒鼙却a提供更多的信息,就是多余。

誤導性注釋?zhuān)汉x不精確或者容易引起誤導的注釋。

循規性注釋?zhuān)好總(gè)函數或者每個(gè)變量都要有注釋的規矩是全然可笑的,只會(huì )搞亂代碼。

日志式注釋?zhuān)涸谟性创a控制系統的今天,這種冗長(cháng)的記錄只會(huì )讓模塊變得凌亂不堪,應該刪除

廢話(huà)注釋?zhuān)簩︼@然之事喋喋不休,毫無(wú)新意?创a的人員,也幾乎對其視而不見(jiàn)。因此用整理代碼的決心替代廢話(huà)的沖動(dòng),會(huì )使你成為更優(yōu)秀的程序員。

可怕的廢話(huà):在知名開(kāi)源庫的J**adoc中,也可以看到復制黏貼錯誤,意思就是變量不一樣,注釋卻一樣。

位置標記:少用標記欄,比如//Action//////////////////////////////,特定函數放在這個(gè)下面,多數時(shí)候是在不必要。

括號后面的注釋?zhuān)罕M管對于多層嵌套有幫助,但是更應該使用短小、封裝的函數,如果你想標記右括號,其實(shí)應該做的是縮短函數。

歸屬與署名:源碼控制系統很善于記錄是誰(shuí)在何時(shí)改動(dòng)了什么,沒(méi)有必要用小小的簽名搞臟代碼。比如注釋/*Added by Rick*/

注釋掉的代碼:直接把代碼注釋掉是討厭的做法,別人可能認為其一定有原因才留在這里不敢刪除,最后注釋掉的代碼像渣滓一樣堆在那里,別這么干!

信息過(guò)多的注釋?zhuān)簞e再注釋中增加歷史性話(huà)題或者無(wú)關(guān)的細節描述。

不明顯的聯(lián)系:注釋的作用是解釋未能自我解釋的代碼,如果本身還需要解釋就沒(méi)有必要了。

函數頭:短函數不需要太多注釋?zhuān)恍枰獙?xiě)一個(gè)好名字就比注釋強得多!

四 關(guān)于代碼格式的規則


你應該保持良好的代碼格式,選用一套管理代碼格式的簡(jiǎn)單規則,然后貫徹實(shí)施。如果在團隊中工作,則團隊應該一致同意采用一套簡(jiǎn)單的格式規則,所有成員都要遵從。使用能幫你應用這些格式規則的自動(dòng)化工具會(huì )很有幫助。

1、格式的目的

原始代碼修改很久之后,其代碼風(fēng)格和可讀性仍會(huì )影響到可維護性和擴展性。

代碼格式關(guān)乎溝通,而溝通時(shí)專(zhuān)業(yè)開(kāi)發(fā)者的頭等大事!

哪些代碼格式方面能幫助我們溝通呢?

2、垂直格式

垂直尺寸

單個(gè)文件的長(cháng)度尺寸與可理解性相關(guān),統計數據表明,用大多數為200行到500行的單個(gè)文件可以構造出出色的系統,短文件通常比長(cháng)文件容易理解!

函數布局

函數名稱(chēng)應該足夠告訴我們是否在正確的模塊中,源文件頂部應該給出高層次的概念和算法,細節應該向下逐次展開(kāi),直至源文件中最低層的函數和細節。就像報紙一樣,標題統領(lǐng)提綱概要,內容逐次展開(kāi)細節。

空行

在包聲明、函數之間、代碼塊之間應該使用空行隔開(kāi),這條簡(jiǎn)單的規則極大的影響到代碼的視覺(jué)外觀(guān)?瞻仔凶鳛橐粭l線(xiàn)索,標示出獨立的概念。

靠近 如果說(shuō)空白行隔開(kāi)了概念,靠近的代碼則暗示了他們之間的緊密聯(lián)系。因此關(guān)系緊密的應該互相靠近.

垂直距離

全局變量聲明應該放到文件第一個(gè)函數聲明前,局部變量聲明放到函數頂部。相關(guān)函數應該放在一起,調用者放在被調用者上面,這樣就能輕易找到被調用函數,極大增強模塊的可讀性

3、橫向格式

行寬

一行代碼應該多寬?統計數據表明,70%的代碼行少于60個(gè)字符,代碼行應該盡量短小,死守80字節有點(diǎn)僵化,但是不要超過(guò)100字符或者120字符。簡(jiǎn)單的規則是無(wú)需向右拖動(dòng)滾動(dòng)條,就可以看到全部代碼。

水平區隔與靠近

在運算符號兩端(乘號除外,因其優(yōu)先級較高,多數格式化工具都忽視優(yōu)先級)、函數名和右括號之間之間,函數參數之間增加空格!

水平對齊

經(jīng)驗表明一組類(lèi)聲明中的變量名、或者賦值語(yǔ)句的右值對齊沒(méi)有什么實(shí)際作用,因此左端對齊,使用同樣的空格區分規則即可。

縮進(jìn)

有縮進(jìn)的代碼結構,閱讀時(shí)可以很容易查找新的聲明、變量、類(lèi)和函數塊,否則就需要折騰一番才能明白,程序員應該依賴(lài)縮進(jìn)模式(在python中強制使用縮進(jìn)表示for循環(huán)的范圍,C語(yǔ)言中使用大括號,但是也要依賴(lài)縮進(jìn)增強可讀性)。

空范圍

有時(shí)while或for語(yǔ)句的語(yǔ)句體為空,如下所示.右端的分號很難看見(jiàn),容易讓人迷惑。

while(dis.read(buf,0,readBufferSize) != 1);

因此最好改為如下格式

while(dis.read(buf,0,readBufferSize) != 1)

{

}

團隊規則

在團隊中,各成員應該采用一致的代碼格式,如果各自風(fēng)格不同,會(huì )增加項目代碼的復雜度。

五 單元測試


過(guò)去10年來(lái),編程專(zhuān)業(yè)領(lǐng)域進(jìn)步很大,特別是敏捷和TDD(測試驅動(dòng)開(kāi)發(fā))運動(dòng)鼓舞了很多程序員編寫(xiě)單元測試。TDD要我們在編寫(xiě)生產(chǎn)代碼之前先編寫(xiě)測試,其還有三大定律:

定律一:再編寫(xiě)不能測試通過(guò)的測試驅動(dòng)前,不可編寫(xiě)生產(chǎn)代碼

定律二:只可編寫(xiě)剛好無(wú)法通過(guò)的單元測試,不能編譯也不算通過(guò)

定律三:只可編寫(xiě)剛好足以通過(guò)當前失敗測試的生產(chǎn)代碼。

這些定律要求測試與生產(chǎn)代碼一起編寫(xiě),測試代碼先寫(xiě),這樣寫(xiě)程序,測試將覆蓋所有生產(chǎn)代碼。

1、保持測試的整潔

測試代碼和生產(chǎn)代碼一樣,需要被思考、設計和照料,像生產(chǎn)代碼一樣整潔

正是單元測試讓你的代碼可擴展、可維護、可復用。如果沒(méi)有測試,每次修改都可能帶來(lái)缺陷,無(wú)論架構如何有擴展性,設計劃分如何好,如果沒(méi)有單元測試,你的改動(dòng)都可能帶來(lái)不可預知的缺陷。

2、整潔的測試

整潔的唯一要素的就是可讀性,在單元測試中,可讀性比生產(chǎn)代碼還重要。如何做到可讀性?就是要明確、簡(jiǎn)潔和具有足夠的表達力。

測試要采用構造-操作-檢驗模式,每個(gè)測試均要可以清晰的拆分為三個(gè)環(huán)節,第一個(gè)環(huán)節構造測試數據,第二個(gè)環(huán)節操作測試數據,第三個(gè)環(huán)節檢驗操作是否得到期望的結果。

3、每個(gè)測試一個(gè)斷言

單個(gè)測試函數有且僅有一個(gè)斷言是個(gè)好準則。

每個(gè)測試做測試一個(gè)概念,如果一個(gè)測試測量三件事情,可能會(huì )導致遺漏。

4、整潔的5條規則

快速(fast),測試應該快速運行,你才能想要頻繁運行它,如果不頻繁運行,就不能盡早發(fā)現問(wèn)題。

獨立(Independent),測試應該互相獨立,從而可以單獨運行每個(gè)測試。

可重復(Repeatable),測試應該在任何環(huán)境中重復通過(guò),否則當前環(huán)境具備時(shí),你也會(huì )無(wú)法運行測試。

自足驗證(Self-Validating),測試應該有布爾值輸出去,無(wú)論如何不應該查看日志文件來(lái)確認測試是否通過(guò)。

及時(shí)(Timely),測試應該及時(shí)編寫(xiě),如果在生產(chǎn)代碼之后編寫(xiě)測試,你會(huì )發(fā)現代碼難以測試。
本文地址:http://selenalain.com/thread-171767-1-1.html     【打印本頁(yè)】

本站部分文章為轉載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀(guān)點(diǎn)和對其真實(shí)性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問(wèn)題,我們將根據著(zhù)作權人的要求,第一時(shí)間更正或刪除。
wk978 發(fā)表于 2016-8-13 19:51:48
代碼整潔之道
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页