趙君喆,鐘良驥,盧社階,聞 彬,戴文華
(湖北科技學(xué)院 計算機科學(xué)與技術(shù)學(xué)院,湖北 咸寧 437100)
代碼是程序員思維的體現(xiàn),開發(fā)者如何通過代碼向維護(hù)者傳遞自己的思路和想法?這需要開發(fā)者盡可能地寫出讓大多數(shù)程序員都容易理解的代碼,也就是可讀性強的代碼。代碼的可讀性包括清晰的思路,流暢的邏輯以及規(guī)范的風(fēng)格。采用公認(rèn)的設(shè)計模式、流行的算法、常見的功能實現(xiàn)套路,避免“聰明”、“微妙”的技巧,都有助于體現(xiàn)代碼邏輯和思路,這些方面研究者甚多,本文不作深入討論。
代碼閱讀者對一個程序最直觀的感受是該程序的代碼風(fēng)格(Coding Style)。代碼1是一段C語言程序,有過網(wǎng)絡(luò)編程經(jīng)驗的開發(fā)者大概可以看出這是一個解析并處理網(wǎng)絡(luò)層數(shù)據(jù)包的函數(shù)。但是對一個沒有網(wǎng)絡(luò)編程經(jīng)驗的開發(fā)者來說,這段代碼讓人感到驚慌。變量pp表示什么?常數(shù)14表示什么?沒有注釋,格式混亂,整段代碼無法理解。
相比代碼1,具有相同功能的代碼2則非常容易理解。從軟件工程學(xué)的角度出發(fā),任何代碼應(yīng)該可以讓任何專業(yè)人員來維護(hù)。因此,遵循良好的代碼風(fēng)格,是軟件高效開發(fā)和維護(hù)的基礎(chǔ)。什么才是良好的代碼風(fēng)格?行業(yè)并沒有嚴(yán)格的標(biāo)準(zhǔn),但是大多數(shù)的軟件維護(hù)人員都希望開發(fā)人員能注意下面幾點。
變量、函數(shù)、類、源文件的名字會給代碼閱讀者帶來很多信息,包括正面的和負(fù)面的。良好的命名習(xí)慣,可以大大減少代碼維護(hù)者的閱讀開銷。規(guī)范地命名一般遵循以下原則:
1.為變量、函數(shù)、類和文件起一個有含義的名字。一個有具體含義的名字往往可以告訴人們這個對象是什么、起什么作用。
表1 命名對比
3.用詞性和大小寫來區(qū)分命名對象的種類。代碼的含義盡可能符合現(xiàn)實世界,所以名字的詞性也盡量符合命名對象的自然屬性。例如一般變量和類的名字采用名詞,函數(shù)的名字采用動詞。比如,class Duck{}、Duck greenDuck、greenDuck.Fly()。如例所示,有些名字是由幾個單詞組成,所以在名字中有的字母大寫,是為了界定單詞。有些程序員習(xí)慣將自定義的類名和函數(shù)名的首字母大寫,而變量的首字母小寫。其主要目的是為了將自定義的類及函數(shù)與系統(tǒng)和庫的類型及函數(shù)區(qū)分開。
4.名字?jǐn)y帶更多信息。行內(nèi)有些命名習(xí)慣讓名字?jǐn)y帶更多的信息,如著名的“匈牙利命名法”。該命名法則在變量前面帶上類型或?qū)傩孕畔ⅲ热鏵loat型變量就以f為名字的開頭,指針變量就以為p為名字的開頭,成員變量以m_開頭,全局變量以 g_開頭等等。如:fRate、pWinHandle、m_color、g_nameMap等都是遵循匈牙利命名法的名字。
代碼反映出程序員的思維流,當(dāng)代碼的維護(hù)者順著代碼的邏輯行云流水般地閱讀下來,他會覺得這段代碼就像一篇文章。事實上,有些代碼中存在著不少噪聲,這些噪聲往往會干擾甚至阻斷代碼閱讀者的思維。這些噪聲包括以下因素:
1.奇異數(shù)(Magic Number)。有些代碼中會出現(xiàn)突如其來的數(shù)字,這些數(shù)字又不帶任何字面的意思,所以當(dāng)代碼維護(hù)者讀到這里的時候,往往會費盡心思來弄清楚這些數(shù)字代表著什么。代碼1中的14、6、17等數(shù)字就是奇異數(shù),當(dāng)它們被替換成代碼3中的ETHER_HEAD_LEN、PROTOCOL_TCP、PROTOCOL_UDP后,代碼的可讀性大大增強。所以定義有意義的宏常量是避免奇異數(shù)的好辦法。
2.多函數(shù)出口(Multiple Return)。函數(shù)作為一個功能性模塊體現(xiàn)出邏輯的封裝性,既然函數(shù)只有一個入口,那么最好只有一個出口。否則的話,代碼閱讀者還要額外考慮函數(shù)異常返回時的上下文安全情況,例如多個出口的函數(shù)在資源管理上就頗有不便:
在代碼3中,錯誤情況發(fā)生時忘記釋放資源就返回了,導(dǎo)致內(nèi)存泄露。不過也可以在每個return前都寫上一段釋放資源的代碼避免內(nèi)存泄露,但如果return過多,代碼不可避免的冗長重復(fù),同樣降低了可讀性。因此可以修改為代碼4的形式,將函數(shù)設(shè)置唯一的出口,資源統(tǒng)一在出口前釋放,這樣的邏輯更加合理。
3.無條件跳轉(zhuǎn)。多年來大量的C開者證實,頻繁使用goto等一些無條件跳轉(zhuǎn)語句會導(dǎo)致程序邏輯混亂,很難維護(hù)。所以在軟件開發(fā)中,應(yīng)該盡量避免goto、setjmp、longjmp等跳轉(zhuǎn)語句。
2)理論與實踐相結(jié)合,緊跟當(dāng)前軟件技術(shù)發(fā)展的前沿,熟悉當(dāng)前軟件項目開發(fā)流程和開發(fā)工具,強化編程能力,培養(yǎng)學(xué)生具有扎實的基礎(chǔ)理論知識和較強的工程項目應(yīng)用能力、培養(yǎng)良好的職業(yè)素養(yǎng)和創(chuàng)新能力作為人才培養(yǎng)目標(biāo)的重心,緊跟并培養(yǎng)以大數(shù)據(jù)為核心,移動互聯(lián)網(wǎng)等新一代信息技術(shù)產(chǎn)業(yè)所需的高級應(yīng)用型軟件人才。
4.復(fù)雜的邏輯表達(dá)式。計算機解析處理大量的“與”、“或”、“非”等邏輯關(guān)系很容易,但人腦理解卻很難。例如,代碼5中的if條件理解起來需要花費很大的代價,但如果將邏輯表達(dá)式切分成多個if來處理,如代碼6,雖然代碼量略增,但可讀性更強。
眾所周知,只要語法正確,再凌亂的格式也絲毫不妨礙編譯器對代碼的理解。但人卻不同,混亂不堪的格式總是讓代碼的閱讀者不知所措。井井有條的代碼格式不僅讓人看上去賞心悅目,更能節(jié)省代碼的閱讀時間。講究代碼格式實際上就是優(yōu)化代碼的排版,程序開發(fā)者在長年累月的工作中積累了一些國際認(rèn)可的代碼排版經(jīng)驗。
1.縮進(jìn)。子模塊通過縮進(jìn)一個單位來體現(xiàn)代碼的邏輯層次,這個單位一般是4個空格。有些開發(fā)者習(xí)慣用tab縮進(jìn),但是不同的編輯器顯示tab的縮進(jìn)大小不一定相同,層次結(jié)構(gòu)分明的代碼在另一個編輯器里可能顯示的很混亂。所以一般建議在編輯器中設(shè)置:將tab替換成4個空格。
2.花括號?;ɡㄌ柕母袷街挥袃煞N習(xí)慣,各有優(yōu)劣,但同一個工程中應(yīng)該保持一致性。
3.對齊。每個程序塊的代碼都應(yīng)該對齊,這樣能更清晰地體現(xiàn)出程序塊之間的邏輯層次。還有一些常見的對齊習(xí)慣,比如變量聲明定義對齊、參數(shù)對齊等,目的都是為了讓代碼看起來更清晰。
4.嵌套。大規(guī)模的嵌套條件語句會讓程序呈現(xiàn)階梯狀縮進(jìn)形式,如代碼4里if語句嵌套if語句。這樣的代碼雖然有規(guī)范地縮進(jìn)和對齊,但如果if語句很長,閱讀者將很難匹配花括號。所以這種情況可將代碼4改成代碼8。
代碼注釋是代碼作者為代碼讀者提供的輔助信息,這些信息包括對功能的描述、對邏輯的解釋以及對易混淆處的提醒等等。
沒有注釋的代碼,即便是代碼作者,一個月后去閱讀,也會有很大的理解障礙。雖然書寫注釋是件乏味而麻煩的事情,但是對于代碼的維護(hù)者來說,好的注釋可以大幅提高代碼的閱讀速度。但是不合時宜或表達(dá)不清的注釋不但不能幫助代碼維護(hù)者閱讀代碼,有時還會干擾或誤導(dǎo)代碼的讀者。
書寫注釋一般應(yīng)參考以下幾點:
1.注釋用語。好的注釋應(yīng)當(dāng)言簡意賅,條理清晰,不應(yīng)將簡單的問題復(fù)雜化,亦不可將復(fù)雜的問題簡單化。此外,如果考慮產(chǎn)品市場的擴展性,注釋語言可以采用英語。
2.文件注釋。比較規(guī)范的文件注釋包括:工程信息、版權(quán)信息、版權(quán)許可信息、工程名、文件描述、作者、版本和修改歷史等。
3.類注釋。格式類似于文件注釋,但是注釋內(nèi)容僅需包括:類名、類功能描述、類接口及使用說明。
4.函數(shù)注釋。格式類似于類注釋,內(nèi)容包括 :函數(shù)名、函數(shù)功能、參數(shù)說明、返回值說明。
5.變量注釋。類的數(shù)據(jù)成員以及全局變量最好注明其含義和用途,這樣的注釋一般采用行注釋方式放在變量的上一行。
6.實現(xiàn)注釋。在代碼中一些機巧、晦澀、有趣、重要的地方應(yīng)該加上實現(xiàn)注釋。如果是對程序塊注釋,一般采用行注釋塊注釋放在程序塊的上面;如果是對某語句注釋,一般采用行注釋緊鄰語句末尾。
7.提醒注釋。有時候程序員寫的一些看上去“不正?!钡拇a,需要提醒閱讀者這是有意為之。比如:未實現(xiàn)的功能需要注釋“TODO”,switch的case中有意不用break時需要注釋“Flow Down”。
歸根結(jié)底,無論采用什么樣的代碼風(fēng)格,最重要的一點是要保持風(fēng)格的一致性。一個工程,從開頭使用了一種風(fēng)格,那么后面的所有代碼就應(yīng)該延續(xù)之前的風(fēng)格。遵循軟件工程學(xué)的思想,應(yīng)參照以下幾個原則來保持代碼風(fēng)格的一致性:
1.軟件開發(fā)商制訂內(nèi)部統(tǒng)一的代碼風(fēng)格框架,并對所有開發(fā)者進(jìn)行代碼規(guī)范化培訓(xùn),從而保證企業(yè)內(nèi)部代碼的易維護(hù)性。
2.項目啟動時制訂項目代碼風(fēng)格細(xì)則,嚴(yán)格約束參與相同項目成員的代碼風(fēng)格,以此保證項目整體的代碼風(fēng)格一致性。
3.維護(hù)項目時,以被維護(hù)項目的代碼風(fēng)格為標(biāo)準(zhǔn),保證被維護(hù)項目的代碼風(fēng)格的持續(xù)性。