在你的代碼中自動(dòng)實(shí)現(xiàn)設(shè)計(jì)規(guī)范在你的工具箱中增加Hammurapi—一個(gè)遵循設(shè)計(jì)的解決方案作者:Sidharth Sankar翻譯:xMatrix版權(quán)聲明:可以任意轉(zhuǎn)載,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必以超鏈接形式標(biāo)明文章原始出處和作者信息及本聲明
作者:
Sidharth Sankar;
xMatrix原文地址:
http://www.javaworld.com/javaworld/jw-04-2005/jw-0418-hammurapi.html中文地址:
http://www.matrix.org.cn/resource/article/43/43890_design_guidelines.html關(guān)鍵詞: design guidelines
摘要設(shè)計(jì)規(guī)范只表示純粹的想法;但項(xiàng)目的成功來說,實(shí)現(xiàn)這些規(guī)范是必須的。傳統(tǒng)的實(shí)現(xiàn)方式是代碼評(píng)審。Hammurapi是一個(gè)遵循設(shè)計(jì)的工具,提供了自動(dòng)而且一致的方式來實(shí)現(xiàn)設(shè)計(jì)規(guī)范,因此使代碼評(píng)審更加有效而輕松。在這篇文章中,作者介紹了Hammurapi的使用,并與其他類似工具進(jìn)行比較,最后還給出演示如何使用的例子。
作為一個(gè)J2EE架構(gòu)師,我需要分發(fā)詳細(xì)設(shè)計(jì)給項(xiàng)目團(tuán)隊(duì)。通過UML模型,我也會(huì)分發(fā)那些捕獲最佳實(shí)踐的設(shè)計(jì)規(guī)范。例如,在Struts應(yīng)用中,我推薦避免在Action類中使用實(shí)例變量,因?yàn)锳ction類是單例的,而且多個(gè)線程同時(shí)訪問一個(gè)Action類實(shí)例是很平常的。其他例子如在任何DAO應(yīng)用中,一個(gè)重要的設(shè)計(jì)方針是關(guān)閉所有打開的數(shù)據(jù)庫資源,如果沒有這么做通常將導(dǎo)致災(zāi)難,尤其是在一個(gè)產(chǎn)品環(huán)境中。
想法是很好的,但是實(shí)現(xiàn)才是關(guān)鍵?,F(xiàn)在最常用的實(shí)現(xiàn)設(shè)計(jì)規(guī)范的方法是做代碼評(píng)審,通常是有經(jīng)驗(yàn)的成員檢查代碼來找出不符合規(guī)范的地方。這些代碼可能是沒有遵守編碼規(guī)范或者設(shè)計(jì)規(guī)范。
這是一種非常低效的方法,主要表現(xiàn)在兩方面:1、這需要兩種資源(開發(fā)人員和評(píng)審人員)。2、質(zhì)量變成評(píng)審人員的職責(zé)。此外,在我的經(jīng)歷中,由于評(píng)審人員過于重視規(guī)范,使得他們與開發(fā)人員對(duì)立起來,而這對(duì)一個(gè)團(tuán)隊(duì)來說是不好的。
許多年前,我接觸過Checkstyle,這是一個(gè)自動(dòng)強(qiáng)制代碼規(guī)范的工具。他與Ant無縫集成并且由基于XML配置文件來驅(qū)動(dòng)。
Hammurapi是一個(gè)與Checkstyle類似的工具,只是他用來強(qiáng)制設(shè)計(jì)規(guī)范。Hammurapi是一個(gè)由Pavel Vlasov開發(fā)的開源軟件,他可以基于一套設(shè)計(jì)規(guī)范來分析代碼庫。當(dāng)他遇到違反規(guī)范的地方,會(huì)在報(bào)告中標(biāo)識(shí)。就像Checkstyle一樣,他與Ant無縫集成并且由基于XML配置文件來驅(qū)動(dòng)。
運(yùn)行Hammurapi你可以直接從命令行運(yùn)行Hammurapi或者作為Eclipse的插件來使用。在這篇幅文章中,我主要討論如何通過Ant任務(wù)來運(yùn)行Hammurapi。
注意:你可以從資源中下載與本文對(duì)應(yīng)的源程序。
與Ant集成非常容易,如下面代碼所示:
1 <target name="design_review" depends="init">
2 <taskdef name="hammurapi" classname="org.hammurapi.HammurapiTask">
3 <classpath>
4 <fileset dir="${hammurapi.home}\lib">
5 <include name="**\*.jar"></include>
6 </fileset>
7 </classpath>
8 </taskdef>
9 <hammurapi>
10 <src dir="src"/>
11 <output dir="docs\review"/>
12 <classpath>
13 <pathelement location="${$log4j.home}\lib\log4j.jar"\/>
14 <pathelement location="${weblogic.home}\lib\weblogic.jar"\/>
15 </classpath>
16 </hammurapi>
17 </target>
第一行定義了一個(gè)design_review的目標(biāo)。他依賴于init目標(biāo)—初始化構(gòu)建的屬性(如第四行的${hammurapi.home})。第二行定義了一個(gè)“hammurapi”新任務(wù)。這個(gè)Ant任務(wù)由org.hammurap.HammurapiTask類實(shí)現(xiàn)。內(nèi)嵌的classpath元素定義了定義這個(gè)任務(wù)所需要的類庫。
第九行聲明了一個(gè)先前定義的hammurapi任務(wù)。運(yùn)行這個(gè)任務(wù)相當(dāng)簡單:只要定義內(nèi)嵌的src元素就可以了,他會(huì)告訴任務(wù)上哪兒查找源程序;然后定義另一個(gè)元素output,這告訴任務(wù)在哪兒輸出報(bào)告。第十行告訴任務(wù)在項(xiàng)目任務(wù)目錄下的src目錄下查找需要評(píng)審的源程序。第十一行告訴任務(wù)輸出報(bào)告到項(xiàng)目目錄下的docs\review中。
第十二行的classpath元素是可選的,他定義了源程序依賴的類庫位置。
Hammurapi帶有100多個(gè)內(nèi)建的檢查器。每一個(gè)對(duì)應(yīng)一個(gè)設(shè)計(jì)規(guī)范。
先前列出的Ant代碼片斷將在log4j源程序上運(yùn)行Hammurapi。代碼將被解壓到項(xiàng)目目錄下的src目錄。圖1顯示了生成的報(bào)告的打開頁面。Hammurapi最令人激動(dòng)的特性就是他生成的全面的報(bào)告。
圖1例示了報(bào)告report.html的主頁,右邊的框架顯示了三個(gè)標(biāo)題:結(jié)果、嚴(yán)重性小結(jié)和文件。
結(jié)果段落顯示整體評(píng)審的統(tǒng)計(jì)。如圖1中所示,26個(gè)包中的179個(gè)文件被評(píng)審了;其中包含6344違反規(guī)范的地方。
嚴(yán)重性小結(jié)段落以表的方式來顯示違反規(guī)范的地方。每一項(xiàng)屬于一個(gè)嚴(yán)重級(jí)別。預(yù)定義的級(jí)別包含1-5級(jí)。級(jí)別1是最嚴(yán)重的。
文件段落(圖2)列出了每一個(gè)被評(píng)審的文件和他所違反的規(guī)范。
雖然嚴(yán)重性小結(jié)段落可以回答如多少空catch塊被找到,文件段落可以回答在Appender.java中多少規(guī)范被違反。但是Hammurapi最有用的功能是他可以在報(bào)告中顯示違反規(guī)范所在的代碼行數(shù)。如讓我們分析一下設(shè)計(jì)規(guī)范ER002:空catch塊(圖2)。點(diǎn)擊數(shù)字列的超鏈就可以顯示報(bào)告這個(gè)違反的文件,如圖3所示。
在很多文件中,報(bào)告顯示LogRecord.java (3)在第307行違反了這個(gè)規(guī)范。在行數(shù)下的超鏈直接鏈接到源程序,如圖4的示。
雖然從整個(gè)代碼庫的運(yùn)行Hammurapi是最常用的方式,但你也可以使用增量的評(píng)審自上一次評(píng)審后改變的代碼。這在代碼庫非常大評(píng)審需要很長時(shí)間時(shí)非常有用。
另一個(gè)運(yùn)行Hammurapi的有效方式是可以處理壓縮文件和其所依賴的并生成壓縮的結(jié)果文件。這種方式在開發(fā)團(tuán)隊(duì)分布在不同的地理位置時(shí)非常有用。在這個(gè)情況下,源程序被壓縮并傳送到遠(yuǎn)程的評(píng)審點(diǎn)。
其他設(shè)計(jì)評(píng)審工具Hammurapi并非是僅有的代碼評(píng)審工具。Metrics也是一個(gè)可以作為Eclipse的很流行的類似工具。然而他有兩個(gè)主要的缺點(diǎn):首先他和Eclipse緊密結(jié)合,想要與Ant結(jié)合相當(dāng)麻煩。由于需要Eclipse的類庫,這使得不使用Eclipse作為IDE的項(xiàng)目不能使用Metrics。其次,你不能用Metrics構(gòu)造自定義的檢查器(Hammurapi可以)--這限制了用戶只能使用內(nèi)建的檢查器。
其他的工具還有PMD。類似于Hammurapi,他與Ant無縫集成而且允許自定義檢查器。然而PMD生成的報(bào)告不如Hammurapi生成的報(bào)告全面。
Hammurapi如何工作Hammurapi這樣的代碼分析工具都帶有語言分析器。語言分析器是一種輸入語言代碼并輸出抽象語法樹的工具。這個(gè)樹上的節(jié)點(diǎn)代表語言標(biāo)識(shí)。例如,考慮一下簡單的算術(shù)表達(dá)式:3+4. 語言分析器會(huì)解析他成為一個(gè)如圖5所示的語法樹。在這個(gè)樹中,節(jié)點(diǎn)+代表操作符標(biāo)識(shí)。節(jié)點(diǎn)3和4是操作數(shù)標(biāo)識(shí)。
Hammurapi使用ANTLR(另一個(gè)語言識(shí)別工具)作為語言分析器。然而ANTLR API是相當(dāng)?shù)讓拥摹楦纳瓶捎眯?,Hammurapi使用另一個(gè)API,基于ANTLR 的JSEL(Java源程序工程類庫),來訪問抽象語法樹。
一旦樹構(gòu)建完成,一種樹遍歷算法就被用來訪問樹中每一個(gè)節(jié)點(diǎn)。每次訪問到一個(gè)節(jié)點(diǎn),一種回調(diào)機(jī)制(Visitor模式)被用來提示相應(yīng)的檢查器。在這些回調(diào)方法中,檢查器收集相關(guān)的信息來確定是否有違反規(guī)范的地方存在。
構(gòu)建自定義的檢查器一個(gè)自定義檢查器可以更好理解Hammurapi框架。如前面所提,一種Struts的最佳實(shí)踐是避免Action類中的實(shí)例變量。所以我們會(huì)構(gòu)建一個(gè)自定義檢查器ActionClassInspector,他掃描源程序中的Action類,如果一個(gè)Action類被發(fā)現(xiàn),他就掃描是否存在實(shí)例變量。如果一個(gè)以上的實(shí)例變量被發(fā)現(xiàn),他就標(biāo)識(shí)出相應(yīng)的違反。
圖6例示了ActionClassInspector類的變量和方法。所有的檢查器都繼承自org.hammurapi.InspectorBase類。
圖7例示了Hammurapi框架激活A(yù)ctionClassInspector類的回調(diào)方法的時(shí)序圖??蚣芙馕鲈闯绦虿?gòu)建一個(gè)抽象語法樹,然后訪問樹中的每一個(gè)節(jié)點(diǎn)。當(dāng)一個(gè)類節(jié)點(diǎn)被訪問時(shí),他調(diào)用visit( v:VariableDefinition )方法。因?yàn)橥ǔR粋€(gè)類可能包含多個(gè)變量,這個(gè)方法可能會(huì)被調(diào)用多次。
下面的代碼顯示了visit( c:Class )方法:
1 public void visit( com.pavelvlasov.jsel.Class c ) throws Exception
2 {
3 isActionClass = c.isKindOf( "org.apache.struts.action.Action");
4
5 return;
6 }
這個(gè)方法負(fù)責(zé)確定是否一個(gè)特定的類是Action類。這個(gè)測(cè)試在第三行被執(zhí)行。如果測(cè)試是肯定的,那么isActionClass被設(shè)置為真。這個(gè)規(guī)范僅應(yīng)用于Action類。
下面的代碼例示了visit( v:VariableDefinition )方法:
1 public void visit( com.pavelvlasov.jsel.VariableDefinition v ) throws Exception
2 {
3 List modifiers;
4 Scope scope;
5
6 if( this.isActionClass )
7 {
8 modifiers = v.getModifiers( );
9 scope = v.getEnclosingScope( );
10 if( scope instanceof com.pavelvlasov.jsel.impl.ClassImpl )
11 {
12 if( modifiers.contains( "static" ) )
13 {
14 ;//Do nothing; this class is compliant.
15 }
16 else
17 {
18 context.reportViolation( (SourceMarker)d, "Violation" );
19 }
20 }
21 }
22
23 return;
24 }
這個(gè)方法負(fù)責(zé)確定是否一個(gè)特定的變量是實(shí)例變量。如果是就報(bào)告一個(gè)違反。第十行確定變量的范圍。這個(gè)測(cè)試過濾掉方法范圍內(nèi)的變量。僅有類或?qū)嵗秶淖兞繒?huì)被繼續(xù)處理。第十二行確定是否一個(gè)變量是靜態(tài)的。如果不是,就報(bào)告一個(gè)違反,如18行所示:
運(yùn)行自定義檢查器只需要對(duì)前面所示例的Ant腳本作一點(diǎn)小小的修改。下面高亮的代碼顯示了修改的地方:
1 <hammurapi>
10 <src dir="src"/>
5 <output dir="docs\review"/>
6 <classpath>
7 <pathelement location="${weblogic.home} \lib\weblogic.jar"></pathelement>
8 <fileset dir="${basedir}\lib">
9 <include name="**\*.jar"></include>
10 </fileset>
11 <pathelement location="${class.dir}"></pathelement>
12 </classpath>
13 <inspectors file="config/inspectors.xml">
14 </inspectors>
17 </hammurapi>
第十三行,包含了可選的元素inspectors,他的file屬性說明了任務(wù)會(huì)去config目錄下的文件inspectors.xml中查找相應(yīng)的檢查器。下面列出了inspectors.xml文件的內(nèi)容:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <inspector-set>
3 <inspector-descriptor>
4 <name>GDL-004</name>
5 <enabled>yes</enabled>
6 <severity>3</severity>
7 <inspector type="hammurapi.ActionClassInspector"></inspector>
8 <description>
9 No instance variables in Action classes.
10 </description>
11 <waivable>yes</waivable>
12 <rationale>
13 Action classes must not have instance variables.
14 </rationale>
15 <resources>Struts best practices.</resources>
16 </inspector-descriptor>
17 </inspector-set>
注意在這里可以用URL來定義inspectors.xml文件的位置。在這種情況下,inspectors.xml文件可以放在遠(yuǎn)程網(wǎng)絡(luò)服務(wù)器上。
總結(jié)總的來說,Hammurapi是一個(gè)優(yōu)秀的遵循設(shè)計(jì)的工具。因?yàn)樗cAnt無縫集成,而Ant可以與任何市面上的IDE集成,所以Hammurapi可以很容易的加入已有的開發(fā)環(huán)境中。
Hammurapi的報(bào)告是非常全面的。他提供了基于規(guī)則和基于文件夾的兩種不同的違反視圖。此外,他在報(bào)告中結(jié)合了源程序,使得報(bào)告整體自包含的。
Hammurapi包含超過100個(gè)內(nèi)建的檢查器。此外,Hammurapi提供了一個(gè)簡單易用的API用來構(gòu)建和管理自定義檢查器。
關(guān)于作者Sidharth Sankar是印度Mohali一家專業(yè)從事J2EE技術(shù)公司(Infosys技術(shù)有限公司)的高級(jí)技術(shù)專家。他擁有華盛頓大學(xué)的計(jì)算機(jī)碩士學(xué)位,他從1996開始從事Java領(lǐng)域的工作,從1999年開始從事J2EE方面的工作。
資源·下載與這篇文章對(duì)應(yīng)的源程序:
http://www.javaworld.com/javaworld/jw-04-2005/hammurapi/jw-0418-hammurapi.zip
·下載Hammurapi
http://www.hammurapi.org
·關(guān)于Hammurapi的五分鐘的介紹:
http://prdownloads.sourceforge.net/hammurapi/Hammurapi.pdf?download
·Hammurapi用戶手冊(cè)
http://prdownloads.sourceforge.net/hammurapi/UserManual.pdf?download
·更多JAVA開發(fā)工具的文章,可以游覽JavaWorld的主題索引的開發(fā)工具部分:
http://www.javaworld.com/channel_content/jw-tools-index.shtml