在你的代碼中自動(dòng)實(shí)現設計規范在你的工具箱中增加Hammurapi—一個(gè)遵循設計的解決方案作者:Sidharth Sankar翻譯:xMatrix版權聲明:可以任意轉載,轉載時(shí)請務(wù)必以超鏈接形式標明文章原始出處和作者信息及本聲明
作者:
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
摘要設計規范只表示純粹的想法;但項目的成功來(lái)說(shuō),實(shí)現這些規范是必須的。傳統的實(shí)現方式是代碼評審。Hammurapi是一個(gè)遵循設計的工具,提供了自動(dòng)而且一致的方式來(lái)實(shí)現設計規范,因此使代碼評審更加有效而輕松。在這篇文章中,作者介紹了Hammurapi的使用,并與其他類(lèi)似工具進(jìn)行比較,最后還給出演示如何使用的例子。
作為一個(gè)J2EE架構師,我需要分發(fā)詳細設計給項目團隊。通過(guò)UML模型,我也會(huì )分發(fā)那些捕獲最佳實(shí)踐的設計規范。例如,在Struts應用中,我推薦避免在A(yíng)ction類(lèi)中使用實(shí)例變量,因為Action類(lèi)是單例的,而且多個(gè)線(xiàn)程同時(shí)訪(fǎng)問(wèn)一個(gè)Action類(lèi)實(shí)例是很平常的。其他例子如在任何DAO應用中,一個(gè)重要的設計方針是關(guān)閉所有打開(kāi)的數據庫資源,如果沒(méi)有這么做通常將導致災難,尤其是在一個(gè)產(chǎn)品環(huán)境中。
想法是很好的,但是實(shí)現才是關(guān)鍵?,F在最常用的實(shí)現設計規范的方法是做代碼評審,通常是有經(jīng)驗的成員檢查代碼來(lái)找出不符合規范的地方。這些代碼可能是沒(méi)有遵守編碼規范或者設計規范。
這是一種非常低效的方法,主要表現在兩方面:1、這需要兩種資源(開(kāi)發(fā)人員和評審人員)。2、質(zhì)量變成評審人員的職責。此外,在我的經(jīng)歷中,由于評審人員過(guò)于重視規范,使得他們與開(kāi)發(fā)人員對立起來(lái),而這對一個(gè)團隊來(lái)說(shuō)是不好的。
許多年前,我接觸過(guò)Checkstyle,這是一個(gè)自動(dòng)強制代碼規范的工具。他與Ant無(wú)縫集成并且由基于XML配置文件來(lái)驅動(dòng)。
Hammurapi是一個(gè)與Checkstyle類(lèi)似的工具,只是他用來(lái)強制設計規范。Hammurapi是一個(gè)由Pavel Vlasov開(kāi)發(fā)的開(kāi)源軟件,他可以基于一套設計規范來(lái)分析代碼庫。當他遇到違反規范的地方,會(huì )在報告中標識。就像Checkstyle一樣,他與Ant無(wú)縫集成并且由基于XML配置文件來(lái)驅動(dòng)。
運行Hammurapi你可以直接從命令行運行Hammurapi或者作為Eclipse的插件來(lái)使用。在這篇幅文章中,我主要討論如何通過(guò)Ant任務(wù)來(lái)運行Hammurapi。
注意:你可以從資源中下載與本文對應的源程序。
與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的目標。他依賴(lài)于init目標—初始化構建的屬性(如第四行的${hammurapi.home})。第二行定義了一個(gè)“hammurapi”新任務(wù)。這個(gè)Ant任務(wù)由org.hammurap.HammurapiTask類(lèi)實(shí)現。內嵌的classpath元素定義了定義這個(gè)任務(wù)所需要的類(lèi)庫。
第九行聲明了一個(gè)先前定義的hammurapi任務(wù)。運行這個(gè)任務(wù)相當簡(jiǎn)單:只要定義內嵌的src元素就可以了,他會(huì )告訴任務(wù)上哪兒查找源程序;然后定義另一個(gè)元素output,這告訴任務(wù)在哪兒輸出報告。第十行告訴任務(wù)在項目任務(wù)目錄下的src目錄下查找需要評審的源程序。第十一行告訴任務(wù)輸出報告到項目目錄下的docs\review中。
第十二行的classpath元素是可選的,他定義了源程序依賴(lài)的類(lèi)庫位置。
Hammurapi帶有100多個(gè)內建的檢查器。每一個(gè)對應一個(gè)設計規范。
先前列出的Ant代碼片斷將在log4j源程序上運行Hammurapi。代碼將被解壓到項目目錄下的src目錄。圖1顯示了生成的報告的打開(kāi)頁(yè)面。Hammurapi最令人激動(dòng)的特性就是他生成的全面的報告。
圖1例示了報告report.html的主頁(yè),右邊的框架顯示了三個(gè)標題:結果、嚴重性小結和文件。
結果段落顯示整體評審的統計。如圖1中所示,26個(gè)包中的179個(gè)文件被評審了;其中包含6344違反規范的地方。
嚴重性小結段落以表的方式來(lái)顯示違反規范的地方。每一項屬于一個(gè)嚴重級別。預定義的級別包含1-5級。級別1是最嚴重的。
文件段落(圖2)列出了每一個(gè)被評審的文件和他所違反的規范。
雖然嚴重性小結段落可以回答如多少空catch塊被找到,文件段落可以回答在A(yíng)ppender.java中多少規范被違反。但是Hammurapi最有用的功能是他可以在報告中顯示違反規范所在的代碼行數。如讓我們分析一下設計規范ER002:空catch塊(圖2)。點(diǎn)擊數字列的超鏈就可以顯示報告這個(gè)違反的文件,如圖3所示。
在很多文件中,報告顯示LogRecord.java (3)在第307行違反了這個(gè)規范。在行數下的超鏈直接鏈接到源程序,如圖4的示。
雖然從整個(gè)代碼庫的運行Hammurapi是最常用的方式,但你也可以使用增量的評審自上一次評審后改變的代碼。這在代碼庫非常大評審需要很長(cháng)時(shí)間時(shí)非常有用。
另一個(gè)運行Hammurapi的有效方式是可以處理壓縮文件和其所依賴(lài)的并生成壓縮的結果文件。這種方式在開(kāi)發(fā)團隊分布在不同的地理位置時(shí)非常有用。在這個(gè)情況下,源程序被壓縮并傳送到遠程的評審點(diǎn)。
其他設計評審工具Hammurapi并非是僅有的代碼評審工具。Metrics也是一個(gè)可以作為Eclipse的很流行的類(lèi)似工具。然而他有兩個(gè)主要的缺點(diǎn):首先他和Eclipse緊密結合,想要與Ant結合相當麻煩。由于需要Eclipse的類(lèi)庫,這使得不使用Eclipse作為IDE的項目不能使用Metrics。其次,你不能用Metrics構造自定義的檢查器(Hammurapi可以)--這限制了用戶(hù)只能使用內建的檢查器。
其他的工具還有PMD。類(lèi)似于Hammurapi,他與Ant無(wú)縫集成而且允許自定義檢查器。然而PMD生成的報告不如Hammurapi生成的報告全面。
Hammurapi如何工作Hammurapi這樣的代碼分析工具都帶有語(yǔ)言分析器。語(yǔ)言分析器是一種輸入語(yǔ)言代碼并輸出抽象語(yǔ)法樹(shù)的工具。這個(gè)樹(shù)上的節點(diǎn)代表語(yǔ)言標識。例如,考慮一下簡(jiǎn)單的算術(shù)表達式:3+4. 語(yǔ)言分析器會(huì )解析他成為一個(gè)如圖5所示的語(yǔ)法樹(shù)。在這個(gè)樹(shù)中,節點(diǎn)+代表操作符標識。節點(diǎn)3和4是操作數標識。
Hammurapi使用ANTLR(另一個(gè)語(yǔ)言識別工具)作為語(yǔ)言分析器。然而ANTLR API是相當底層的。為改善可用性,Hammurapi使用另一個(gè)API,基于A(yíng)NTLR 的JSEL(Java源程序工程類(lèi)庫),來(lái)訪(fǎng)問(wèn)抽象語(yǔ)法樹(shù)。
一旦樹(shù)構建完成,一種樹(shù)遍歷算法就被用來(lái)訪(fǎng)問(wèn)樹(shù)中每一個(gè)節點(diǎn)。每次訪(fǎng)問(wèn)到一個(gè)節點(diǎn),一種回調機制(Visitor模式)被用來(lái)提示相應的檢查器。在這些回調方法中,檢查器收集相關(guān)的信息來(lái)確定是否有違反規范的地方存在。
構建自定義的檢查器一個(gè)自定義檢查器可以更好理解Hammurapi框架。如前面所提,一種Struts的最佳實(shí)踐是避免Action類(lèi)中的實(shí)例變量。所以我們會(huì )構建一個(gè)自定義檢查器ActionClassInspector,他掃描源程序中的Action類(lèi),如果一個(gè)Action類(lèi)被發(fā)現,他就掃描是否存在實(shí)例變量。如果一個(gè)以上的實(shí)例變量被發(fā)現,他就標識出相應的違反。
圖6例示了ActionClassInspector類(lèi)的變量和方法。所有的檢查器都繼承自org.hammurapi.InspectorBase類(lèi)。
圖7例示了Hammurapi框架激活ActionClassInspector類(lèi)的回調方法的時(shí)序圖??蚣芙馕鲈闯绦虿嫿ㄒ粋€(gè)抽象語(yǔ)法樹(shù),然后訪(fǎng)問(wèn)樹(shù)中的每一個(gè)節點(diǎn)。當一個(gè)類(lèi)節點(diǎn)被訪(fǎng)問(wèn)時(shí),他調用visit( v:VariableDefinition )方法。因為通常一個(gè)類(lèi)可能包含多個(gè)變量,這個(gè)方法可能會(huì )被調用多次。
下面的代碼顯示了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è)方法負責確定是否一個(gè)特定的類(lèi)是Action類(lèi)。這個(gè)測試在第三行被執行。如果測試是肯定的,那么isActionClass被設置為真。這個(gè)規范僅應用于A(yíng)ction類(lèi)。
下面的代碼例示了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è)方法負責確定是否一個(gè)特定的變量是實(shí)例變量。如果是就報告一個(gè)違反。第十行確定變量的范圍。這個(gè)測試過(guò)濾掉方法范圍內的變量。僅有類(lèi)或實(shí)例范圍的變量會(huì )被繼續處理。第十二行確定是否一個(gè)變量是靜態(tài)的。如果不是,就報告一個(gè)違反,如18行所示:
運行自定義檢查器只需要對前面所示例的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屬性說(shuō)明了任務(wù)會(huì )去config目錄下的文件inspectors.xml中查找相應的檢查器。下面列出了inspectors.xml文件的內容:
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來(lái)定義inspectors.xml文件的位置。在這種情況下,inspectors.xml文件可以放在遠程網(wǎng)絡(luò )服務(wù)器上。
總結總的來(lái)說(shuō),Hammurapi是一個(gè)優(yōu)秀的遵循設計的工具。因為他與Ant無(wú)縫集成,而Ant可以與任何市面上的IDE集成,所以Hammurapi可以很容易的加入已有的開(kāi)發(fā)環(huán)境中。
Hammurapi的報告是非常全面的。他提供了基于規則和基于文件夾的兩種不同的違反視圖。此外,他在報告中結合了源程序,使得報告整體自包含的。
Hammurapi包含超過(guò)100個(gè)內建的檢查器。此外,Hammurapi提供了一個(gè)簡(jiǎn)單易用的API用來(lái)構建和管理自定義檢查器。
關(guān)于作者Sidharth Sankar是印度Mohali一家專(zhuān)業(yè)從事J2EE技術(shù)公司(Infosys技術(shù)有限公司)的高級技術(shù)專(zhuān)家。他擁有華盛頓大學(xué)的計算機碩士學(xué)位,他從1996開(kāi)始從事Java領(lǐng)域的工作,從1999年開(kāi)始從事J2EE方面的工作。
資源·下載與這篇文章對應的源程序:
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用戶(hù)手冊
http://prdownloads.sourceforge.net/hammurapi/UserManual.pdf?download
·更多JAVA開(kāi)發(fā)工具的文章,可以游覽JavaWorld的主題索引的開(kāi)發(fā)工具部分:
http://www.javaworld.com/channel_content/jw-tools-index.shtml