摘要 設計規范只表示純粹的想法
但項目的成功來說
實現這些規范是必須的
傳統的實現方式是代碼評審
Hammurapi是一個遵循設計的工具
提供了自動而且一致的方式來實現設計規范
因此使代碼評審更加有效而輕松
在這篇文章中
作者介紹了Hammurapi的使用
並與其他類似工具進行比較
最後還給出演示如何使用的例子
作為一個J
EE架構師
我需要分發詳細設計給項目團隊
通過UML模型
我也會分發那些捕獲最佳實踐的設計規范
例如
在Struts應用中
我推薦避免在Action類中使用實例變量
因為Action類是單例的
而且多個線程同時訪問一個Action類實例是很平常的
其他例子如在任何DAO應用中
一個重要的設計方針是關閉所有打開的數據庫資源
如果沒有這麼做通常將導致災難
尤其是在一個產品環境中
想法是很好的
但是實現才是關鍵
現在最常用的實現設計規范的方法是做代碼評審
通常是有經驗的成員檢查代碼來找出不符合規范的地方
這些代碼可能是沒有遵守編碼規范或者設計規范
這是一種非常低效的方法
主要表現在兩方面
這需要兩種資源(開發人員和評審人員)
質量變成評審人員的職責
此外
在我的經歷中
由於評審人員過於重視規范
使得他們與開發人員對立起來
而這對一個團隊來說是不好的
許多年前
我接觸過Checkstyle
這是一個自動強制代碼規范的工具
他與Ant無縫集成並且由基於XML配置文件來驅動
Hammurapi是一個與Checkstyle類似的工具
只是他用來強制設計規范
Hammurapi是一個由Pavel Vlasov開發的開源軟件
他可以基於一套設計規范來分析代碼庫
當他遇到違反規范的地方
會在報告中標識
就像Checkstyle一樣
他與Ant無縫集成並且由基於XML配置文件來驅動
運行Hammurapi 你可以直接從命令行運行Hammurapi或者作為Eclipse的插件來使用
在這篇幅文章中
我主要討論如何通過Ant任務來運行Hammurapi
注意
你可以從資源中下載與本文對應的源程序
與Ant集成非常容易
如下面代碼所示
<target name=
design_review
depends=
init
>
<taskdef name=
hammurapi
classname=
org
hammurapi
HammurapiTask
>
<classpath>
<fileset dir=
${hammurapi
home}\lib
>
<include name=
**\*
jar
></include>
</fileset>
</classpath>
</taskdef>
<hammurapi>
<src dir=
src
/>
<output dir=
docs\review
/>
<classpath>
<pathelement location=
${$log
j
home}\lib\log
j
jar
\/>
<pathelement location=
${weblogic
home}\lib\weblogic
jar
\/>
</classpath>
</hammurapi>
</target>
第一行定義了一個design_review的目標
他依賴於init目標—初始化構建的屬性(如第四行的${hammurapi
home})
第二行定義了一個
hammurapi
新任務
這個Ant任務由org
hammurap
HammurapiTask類實現
內嵌的classpath元素定義了定義這個任務所需要的類庫
第九行聲明了一個先前定義的hammurapi任務
運行這個任務相當簡單
只要定義內嵌的src元素就可以了
他會告訴任務上哪兒查找源程序
然後定義另一個元素output
這告訴任務在哪兒輸出報告
第十行告訴任務在項目任務目錄下的src目錄下查找需要評審的源程序
第十一行告訴任務輸出報告到項目目錄下的docs\review中
第十二行的classpath元素是可選的
他定義了源程序依賴的類庫位置
Hammurapi帶有
多個內建的檢查器
每一個對應一個設計規范
先前列出的Ant代碼片斷將在log
j源程序上運行Hammurapi
代碼將被解壓到項目目錄下的src目錄
圖
顯示了生成的報告的打開頁面
Hammurapi最令人激動的特性就是他生成的全面的報告
educitycn/img_///jpg > 圖
例示了報告l的主頁
右邊的框架顯示了三個標題
結果
嚴重性小結和文件
結果段落顯示整體評審的統計
如圖
中所示
個包中的
個文件被評審了
其中包含
違反規范的地方
嚴重性小結段落以表的方式來顯示違反規范的地方
每一項屬於一個嚴重級別
預定義的級別包含
級
級別
是最嚴重的
文件段落(圖
)列出了每一個被評審的文件和他所違反的規范
educitycn/img_///gif > 雖然嚴重性小結段落可以回答如多少空catch塊被找到
文件段落可以回答在Appender
java中多少規范被違反
但是Hammurapi最有用的功能是他可以在報告中顯示違反規范所在的代碼行數
如讓我們分析一下設計規范ER
空catch塊(圖
)
點擊數字列的超鏈就可以顯示報告這個違反的文件
如圖
所示
educitycn/img_///gif> 在很多文件中
報告顯示LogRecord
java (
)在第
行違反了這個規范
在行數下的超鏈直接鏈接到源程序
如圖
的示
educitycn/img_///gif > 雖然從整個代碼庫的運行Hammurapi是最常用的方式
但你也可以使用增量的評審自上一次評審後改變的代碼
這在代碼庫非常大評審需要很長時間時非常有用
另一個運行Hammurapi的有效方式是可以處理壓縮文件和其所依賴的並生成壓縮的結果文件
這種方式在開發團隊分布在不同的地理位置時非常有用
在這個情況下
源程序被壓縮並傳送到遠程的評審點
其他設計評審工具 Hammurapi並非是僅有的代碼評審工具
Metrics也是一個可以作為Eclipse的很流行的類似工具
然而他有兩個主要的缺點
首先他和Eclipse緊密結合
想要與Ant結合相當麻煩
由於需要Eclipse的類庫
這使得不使用Eclipse作為IDE的項目不能使用Metrics
其次
你不能用Metrics構造自定義的檢查器(Hammurapi可以)
這限制了用戶只能使用內建的檢查器
其他的工具還有PMD
類似於Hammurapi
他與Ant無縫集成而且允許自定義檢查器
然而PMD生成的報告不如Hammurapi生成的報告全面
Hammurapi如何工作 Hammurapi這樣的代碼分析工具都帶有語言分析器
語言分析器是一種輸入語言代碼並輸出抽象語法樹的工具
這個樹上的節點代表語言標識
例如
考慮一下簡單的算術表達式
+
語言分析器會解析他成為一個如圖
所示的語法樹
在這個樹中
節點+代表操作符標識
節點
和
是操作數標識
educitycn/img_///jpg> Hammurapi使用ANTLR(另一個語言識別工具)作為語言分析器
然而ANTLR API是相當底層的
為改善可用性
Hammurapi使用另一個API
基於ANTLR 的JSEL(Java源程序工程類庫)
來訪問抽象語法樹
一旦樹構建完成
一種樹遍歷算法就被用來訪問樹中每一個節點
每次訪問到一個節點
一種回調機制(Visitor模式)被用來提示相應的檢查器
在這些回調方法中
檢查器收集相關的信息來確定是否有違反規范的地方存在
構建自定義的檢查器 一個自定義檢查器可以更好理解Hammurapi框架
如前面所提
一種Struts的最佳實踐是避免Action類中的實例變量
所以我們會構建一個自定義檢查器ActionClassInspector
他掃描源程序中的Action類
如果一個Action類被發現
他就掃描是否存在實例變量
如果一個以上的實例變量被發現
他就標識出相應的違反
圖
例示了ActionClassInspector類的變量和方法
所有的檢查器都繼承自org
hammurapi
InspectorBase類
educitycn/img_///jpg > 圖
例示了Hammurapi框架激活ActionClassInspector類的回調方法的時序圖
框架解析源程序並構建一個抽象語法樹
然後訪問樹中的每一個節點
當一個類節點被訪問時
他調用visit( v:VariableDefinition )方法
因為通常一個類可能包含多個變量
這個方法可能會被調用多次
educitycn/img_///jpg> 下面的代碼顯示了visit( c:Class )方法
public void visit( com
pavelvlasov
jsel
Class c ) throws Exception
{
isActionClass = c
isKindOf(
org
apache
struts
action
Action
);
return;
}
這個方法負責確定是否一個特定的類是Action類
這個測試在第三行被執行
如果測試是肯定的
那麼isActionClass被設置為真
這個規范僅應用於Action類
下面的代碼例示了visit( v:VariableDefinition )方法
public void visit( com
pavelvlasov
jsel
VariableDefinition v ) throws Exception
{
List modifiers;
Scope scope;
if( this
isActionClass )
{
modifiers = v
getModifiers( );
scope = v
getEnclosingScope( );
if( scope instanceof com
pavelvlasov
jsel
impl
ClassImpl )
{
if( ntains(
static
) )
{
;//Do nothing; this class is compliant
}
else
{
context
reportViolation( (SourceMarker)d
Violation
);
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25636.html