Code Review與CheckStyle
本文向大家介紹Code Review的主要內(nèi)容,以及流行的檢查Code Conventions的工具。同時(shí),對(duì)于目前應(yīng)用最為廣泛的CheckStyle的應(yīng)用給出詳細(xì)的介紹,同時(shí),也列舉了很多使用CheckStyle的最佳實(shí)踐。
1. Code Review & Code Conventions
質(zhì)量是衡量一個(gè)軟件是否成功的關(guān)鍵要素。而對(duì)于商業(yè)軟件系統(tǒng),尤其是企業(yè)應(yīng)用軟件系統(tǒng)來說,除了軟件運(yùn)行質(zhì)量、文檔質(zhì)量以外,代碼的質(zhì)量也是非常重要的。軟件開發(fā)進(jìn)行到編碼階段的時(shí)候,最大的風(fēng)險(xiǎn)就在于如何保證代碼的易讀性和一致性,從而使得軟件的維護(hù)的代價(jià)不會(huì)很高。
在軟件開發(fā)的過程中,以下幾種情形隨處可見:
1. 軟件維護(hù)時(shí)間長(zhǎng),而且維護(hù)人員的積極性不高:
做過軟件維護(hù)的開發(fā)人員,尤其是在接手不是自己開發(fā)產(chǎn)品的源碼的時(shí)候,即使有良好的文檔說明,仍然會(huì)對(duì)代碼中冗長(zhǎng)、沒有注釋的段落“嘆為觀止”。理解尚且如此困難,何況要修改或者增加新的功能。因此,很多開發(fā)人員不愿意進(jìn)行軟件維護(hù)的工作。
2. 新的開發(fā)人員融入團(tuán)隊(duì)的時(shí)間比較長(zhǎng):
除了沒有良好的培訓(xùn)、文檔等有效的機(jī)制以外,每個(gè)人一套的編碼風(fēng)格,也容易造成新成員對(duì)于已有代碼的理解不夠,甚至出現(xiàn)偏差。
編碼規(guī)范,作為解決以上問題的方案已經(jīng)得到了很長(zhǎng)時(shí)間的應(yīng)用。而在產(chǎn)品或者項(xiàng)目實(shí)際開發(fā)的過程中,僅有Code Conventions是不能解決Code的問題的。它往往和Code Review配合,作為代碼質(zhì)量保證的手段。
1.1. Code Review的層次與內(nèi)容
Code Review就是審查代碼的質(zhì)量。根據(jù)形式分為兩種,一種是交叉代碼審查,就是自己的代碼由他人來檢查,就象檢查作業(yè)一樣;另一種是代碼會(huì)審,就是以會(huì)議的形式,大家共同審核代碼的質(zhì)量。
Code Review 的目的有[2]:
2 在項(xiàng)目早期就能夠發(fā)現(xiàn)代碼中的BUG;
2 幫助初級(jí)開發(fā)人員學(xué)習(xí)高級(jí)開發(fā)人員的經(jīng)驗(yàn),達(dá)到知識(shí)共享;
2 避免開發(fā)人員犯一些很常見,很普通的錯(cuò)誤;
2 保證項(xiàng)目組人員的良好溝通;
2 項(xiàng)目或產(chǎn)品的代碼更容易維護(hù);
一般情況下,Code Review的內(nèi)容與層次如下:
2 編碼風(fēng)格與代碼規(guī)范一致性:檢查代碼是否符合編碼規(guī)范,確保所有人寫的代碼基本一致;
2 代碼滿足基本的功能要求:檢查代碼的邏輯實(shí)現(xiàn),以及單元測(cè)試的編寫策略,確認(rèn)實(shí)現(xiàn)功能性需求;
2 代碼滿足性能等非功能性需求:非功能性需求一般不便于測(cè)試,需要借助一定的工具和Review人員的素質(zhì),針對(duì)編碼中對(duì)于性能影響的瓶頸給出解決方案;
2 去除冗余,提高代碼可讀性:適當(dāng)使用 Refactorying技術(shù),去除代碼中的Bad Smell;如果有需要,可以Refactorying to Pattern。
1.2. Code Conventions的尷尬境地
從Code Review的層次分析中我們可以看到,Code Conventions是其基礎(chǔ)。而實(shí)際的情況是,在軟件開發(fā)中,兩者都淪為“宣傳口號(hào)”,而非切實(shí)執(zhí)行的實(shí)踐。
造成這種情形的原因有二:
1. Code Conventions是開發(fā)過程的“道德”而非“法律”:很多時(shí)候,由于沒有有效的工具或者輔助手段的支持,是否遵守編碼規(guī)范是依靠開發(fā)人員的“道德素養(yǎng)”-自覺遵守,而非實(shí)際考核的指標(biāo);
2. Code Review的基石不牢:在第一種原因的影響下,Code Review執(zhí)行的過程中,如果花費(fèi)了大量的時(shí)間在代碼規(guī)范的檢查上,那么對(duì)于更為重要的程序執(zhí)行邏輯、性能、易讀性等的評(píng)審?fù)度氲木陀邢薜模欢@種情況反過來也使得對(duì)于編碼規(guī)范的檢查,通常都是走過場(chǎng)。最后,還是每個(gè)人一套規(guī)范,只要最終交付的產(chǎn)品完成指定的功能就可以啦。
2. CheckStyle
面對(duì)以上描述的Code Conventions的尷尬境地,陸續(xù)有開發(fā)人員提出了自己的解決方案。目前,對(duì)于JAVA的代碼規(guī)范的檢查,已經(jīng)有很多成熟的工具,例如CheckStyle、PMD以及Jalopy等[3]。其中,CheckStyle的應(yīng)用非常廣泛,眾多開源項(xiàng)目都使用它作為檢查代碼規(guī)范的工具,尤其是 Jakarta 的很多項(xiàng)目,例如Maven、 Torque等。
2.1. CheckStyle是什么?
CheckStyle是SourceForge下的一個(gè)項(xiàng)目,提供了一個(gè)幫助JAVA開發(fā)人員遵守某些編碼規(guī)范的工具。它能夠自動(dòng)化代碼規(guī)范檢查過程,從而使得開發(fā)人員從這項(xiàng)重要,但是枯燥的任務(wù)中解脫出來[1]。
2.2. CheckStyle檢驗(yàn)的主要內(nèi)容
CheckStyle默認(rèn)提供一下主要檢查內(nèi)容:
2 Javadoc注釋
2 命名約定
2 標(biāo)題
2 Import語(yǔ)句
2 體積大小
2 空白
2 修飾符
2 塊
2 代碼問題
2 類設(shè)計(jì)
2 混合檢查(包活一些有用的比如非必須的System.out和printstackTrace)
從上面可以看出,CheckStyle提供了大部分功能都是對(duì)于代碼規(guī)范的檢查,而沒有提供象PMD和Jalopy那么多的增強(qiáng)代碼質(zhì)量和修改代碼的功能。但是,對(duì)于團(tuán)隊(duì)開發(fā),尤其是強(qiáng)調(diào)代碼規(guī)范的公司來說,它的功能已經(jīng)足夠強(qiáng)大。
2.3. CheckStyle的主要運(yùn)行方式
目前,CheckStyle的版本是3.0,與以前的版本不同,它的配置文件是基于XML而非Properties文件。
它的3.0版本提供了兩種運(yùn)行的方式:
2 命令行工具
2 ANT任務(wù)
同時(shí),CheckStyle目前有很多針對(duì)流行IDE的插件,例如Eclipse、IntelliJ IDEA、JBuilder等。但是,大部分都是基于2.4的版本,新版本的特性不支持,同時(shí)配置也較為復(fù)雜。
因?yàn)橐话闱闆r下,如果與開發(fā)過程與環(huán)境集成起來,編碼規(guī)范的檢查會(huì)更加有效,因此,作為ANT任務(wù)的運(yùn)行方式使用的更加普遍。
在ANT的build.xml文件中添加CheckStyle任務(wù)的步驟如下:
1. 將checkstyle-all-3.1.jar拷貝到項(xiàng)目的LIB目錄;
2. 建立配置文件;
3. 聲明CheckStyle任務(wù):
<taskdef resource="checkstyletask.properties"
classpath="${lib}/checkstyle-all-3.1.jar"/>
4. 建立CheckStyle任務(wù):
<target name="checkstyle">
<checkstyle config="${config}/sun_checks.xml">
<fileset dir="${src}" includes=" **/*.java" />
</checkstyle>
</target>
2.4. 定制CheckStyle
CheckStyle的執(zhí)行基于XML配置文件,它的主要組成部分是:
2 Module:整個(gè)配置文件就是一棵Module樹。根節(jié)點(diǎn)是Checker Module。
2 Properties:它來決定一個(gè)Module如何進(jìn)行檢查。每個(gè)Module都有一個(gè)默認(rèn)值,如果不滿足開發(fā)需求,可以設(shè)定其它的值。
下面是一個(gè)示例:
<module name="MethodLength">
<property name="max" value="60"/>
</module>
它表示,如果方法或者構(gòu)造函數(shù)的長(zhǎng)度超過60行,CheckStyle就會(huì)報(bào)錯(cuò)。而默認(rèn)值是150行。
以下是一段CheckStyle對(duì)于Maven項(xiàng)目源文件的檢查報(bào)告:
Method 'createExpression' is not designed for extension - needs to be abstract, final or empty. 91
Unable to get class information for JellyException. 91
Line has trailing spaces. 93
Line has trailing spaces. 104
Method 'evaluate' is not designed for extension - needs to be abstract, final or empty. 113
Parameter context should be final. 113
Line has trailing spaces. 130
Method 'getExpressionText' is not designed for extension - needs to be abstract, final or empty. 131
Line has trailing spaces. 134
Line has trailing spaces. 135
Method 'toString' is not designed for extension - needs to be abstract, final or empty. 137
Method 'isSupportAntVariables' is not designed for extension - needs to be abstract, final or empty. 156
Method 'setSupportAntVariables' is not designed for extension - needs to be abstract, final or empty. 168
Parameter supportAntVariables should be final. 168
'supportAntVariables' hides a field. 168
Method 'isValidAntVariableName' is not designed for extension - needs to be abstract, final or empty. 183
Parameter text should be final. 183
一般情況下,與IDE集成在一起使用的時(shí)候,點(diǎn)擊出錯(cuò)的條目,可以跳轉(zhuǎn)到相應(yīng)的代碼。
3. CheckStyle的最佳實(shí)踐
3.1. Sun’s Code Conventions的修改
在CheckStyle的最新發(fā)布版本中,有一個(gè)對(duì)于Sun的Java編碼規(guī)范的配置文件信息。但是,其中有很多條目并不一定符合項(xiàng)目開發(fā)的需要。就算是對(duì)于很多優(yōu)秀的開源項(xiàng)目,按照這個(gè)規(guī)范來進(jìn)行檢查,也會(huì)出現(xiàn)成千上萬(wàn)的錯(cuò)誤。
下面提出的一些修改意見,是從實(shí)際項(xiàng)目執(zhí)行過程中總結(jié)出來的,可以作為大家的參考。我們以CheckStyle3.0配置文件的順序來介紹:
1. 去除對(duì)于每個(gè)包都有一個(gè)package.html文件的限制;
<!--<module name="PackageHtml"/>-->
2. 修改對(duì)于JavaDoc Comments的限定:對(duì)于很多使用Code Generator的項(xiàng)目來說,需要將手寫代碼與生成代碼、單元測(cè)試代碼的檢查分開進(jìn)行;
3. 修改對(duì)于體積大小的限制:目前,很多顯示器都是17寸,而且打印方面的限制也比以前有所改善,同時(shí),由于代碼中Factory等模式的運(yùn)用,以及有意義的方法名稱等約定,默認(rèn)每行代碼的長(zhǎng)度(80)是遠(yuǎn)遠(yuǎn)不能滿足要求;對(duì)于方法長(zhǎng)度等等,也應(yīng)該根據(jù)項(xiàng)目情況自行決定:
<module name="FileLength"/>
<module name="LineLength">
<property name="max" value="120"/>
</module>
<module name="MethodLength">
<property name="max" value="300"/>
</module>
<module name="ParameterNumber"/>
4. 修改對(duì)于Throws的的限制:允許Throws Unchecked Exception以及Throws Subclass Of Another Declared Exception。
<module name="RedundantThrows">
<property name="allowUnchecked" value="true"/>
<property name="allowSubclasses" value="true"/>
</module>
5. 修改成員變量的可視性:一般情況下,應(yīng)該允許Protected Members以及Package Visible Members。
<module name="VisibilityModifier">
<property name="protectedAllowed" value="true"/>
<property name="packageAllowed" value="true"/>
</module>
3.2. CheckStyle應(yīng)用的最佳實(shí)踐
采用CheckStyle以后,編碼規(guī)范的檢查就變得及其簡(jiǎn)單,可以作為一項(xiàng)切實(shí)可行的實(shí)踐加以執(zhí)行。
一般情況下,在項(xiàng)目小組中引入CheckStyle可以按照下面的步驟進(jìn)行:
1. 強(qiáng)調(diào)Code Review與Code Conventions的重要作用;
2. 介紹CheckStyle;
3. 初步應(yīng)用CheckStyle:參照CheckStyle附帶的配置文件,酌情加以剪裁,在項(xiàng)目的Ant配置文件中,添加CheckStyle任務(wù),可以單獨(dú)執(zhí)行;
4. 修改、定型CheckStyle的配置文件:按照基本配置文件執(zhí)行一段時(shí)間(2~3周),聽取開發(fā)人員的反饋意見,修改配置信息;
5. 作為開發(fā)過程的日常實(shí)踐,強(qiáng)制執(zhí)行CheckStyle:穩(wěn)定CheckStyle的配置信息,同時(shí)將CheckStyle任務(wù)作為Build的依賴任務(wù)或者配置源碼控制系統(tǒng)(目前,CheckStyle可以與CVS有效集成),使得代碼在加入系統(tǒng)之前必須通過檢查。
同時(shí)需要指出的是,CheckStyle的有效執(zhí)行需要依賴兩個(gè)條件:
2 Ant的廣泛應(yīng)用:CheckStyle基于Ant執(zhí)行的方式比較容易,而且可以在項(xiàng)目?jī)?nèi)容形成一致的執(zhí)行環(huán)境。同時(shí),也比較容易與其它任務(wù),例如Build等發(fā)生關(guān)聯(lián)。
2 IDE Format Code的強(qiáng)大功能:由于CheckStyle本身并沒有提供很強(qiáng)大的Code Format等功能,因此,需要借助IDE的幫助,從而使得在發(fā)生錯(cuò)誤的時(shí)候,可以很容易的進(jìn)行修復(fù)。目前,主流的Java IDE都提供了這方面的功能,IDEA在這方面尤其突出。它提供的統(tǒng)一、可定義的Code Format Template(項(xiàng)目小組內(nèi)部可以使用統(tǒng)一模板)以及方便的快捷鍵功能(Ctrl+Alt+T:Format Code, Ctrl+Alt+O:Optimize Import等)。
4. 結(jié)論
利用CheckStyle可以方便的對(duì)于編碼的Code Conventions進(jìn)行檢查,同時(shí),也有效地減少了Code Review的工作,使得Reviw人員的精力更多的集中到邏輯和性能檢查。
參考文獻(xiàn):
[1] CheckStyle Project Website
[2] Code Review 理論與實(shí)戰(zhàn) CSDN
[3] 輕松有效檢查Java代碼的三個(gè)工具 ZDNet China