程式碼質量概述
怎樣辨別一個專案程式碼寫得好還是壞?優秀的程式碼和腐化的程式碼區別在哪裡?怎麼讓自己寫的程式碼既漂亮又有生命力?接下來將對程式碼質量的問題進行一些粗略的介紹。也請有過程式碼質量相關經驗的朋友提出寶貴的意見。
程式碼質量所涉及的5個方面,編碼標準、程式碼重複、程式碼覆蓋率、依賴項分析、複雜度分析。這5方面很大程式上決定了一份程式碼的質量高低。我們分別來看一下這5方面:
編碼標準:這個想必都很清楚,每個公司幾乎都有一份編碼規範,類命名、包命名、程式碼風格之類的東西都屬於其中。
程式碼重複:顧名思義就是重複的程式碼,如果你的程式碼中有大量的重複程式碼,你就要考慮是否將重複的程式碼提取出來,封裝成一個公共的方法或者元件。
程式碼覆蓋率:測試程式碼能執行到的程式碼比率,你的程式碼經過了單元測試了嗎?是不是每個方法都進行了測試,程式碼覆蓋率是多少?這關係到你的程式碼的功能性和穩定性。
依賴項分析:你的程式碼依賴關係怎麼樣?耦合關係怎麼樣?是否有迴圈依賴?是否符合高內聚低耦合的原則?透過依賴項分析可以辨別一二。
複雜度分析:以前有人寫的程式巢狀了10層 if else你信嗎?圈複雜度之高,讓人難以閱讀。透過複雜度分析可以揪出這些程式碼,要相信越優秀的程式碼,越容易讀懂。
上面解釋了程式碼質量相關的5個方面,在實際開發環境中,已經有很多工具為我們解決以上5個方面的問題,下列5個eclipse外掛分別對這5個問題有很好的支援:
編碼標準:CheckStyle 外掛URL:http://eclipse-cs.sourceforge.net/update/
程式碼重複:PMD的CPD 外掛URL:http://pmd.sourceforge.net/eclipse/
程式碼覆蓋率:Eclemma 外掛URL:http://update.eclemma.org
依賴項分析:JDepend 外掛URL:http://andrei.gmxhome.de/eclipse/
複雜度分析:Eclipse Metric 外掛URL:http://metrics.sourceforge.net/update
注:某些外掛需要科學上網才能更新
編碼標準(CheckStyle的使用)
在eclipse上安裝好了CheckStyle外掛後,我們來建一個類用它跑一下。這個類很簡單,一個常見的使用者實體,包含了id,使用者名稱、密碼、郵件等屬性,幷包含get set方法,一個標準的POJO。執行CheckStyle檢查一下:
一個我們平時再普通不過的一個類,被checkstyle弄出這麼多問題,情何以堪,我們來看看究竟是什麼情況?
看一下這些警告資訊:
line 1、,說缺少package-info.java檔案。
line 35、,getId不是繼承的方法,必須指定abstract,final或空。另外也缺少java doc註釋。
這個類基本就這四類毛病,缺少package-info.java檔案,這個檔案是做什麼的呢?他是用來描述包註釋的類,有一定的特殊性,要想詳細瞭解請百度。如果對你的專案沒有太大的影響,可以忽略它。配置CheckStyle的方法我們等會再說。第一句註釋要以“.”結尾,這看你的習慣,你確定需要這個,你就保留,不需要就忽略。缺少java doc,對於java類的屬性來說,註釋是必要的,所以這個要保留。不是繼承的方法,需要加上final關鍵字,如果你有這個習慣,就保留,反之忽略。
我們這裡只是建立了一個最簡單的類用CheckStyle來檢查,隨著你的類程式碼越來越多,邏輯越來越複雜,CheckStyle能檢查出來的毛病也越來越多。常見的CheckStyle錯誤有這些:
1.Type is missing a javadoc commentClass
缺少型別說明
2.“{” should be on the previous line
“{” 應該位於前一行
3.Methods is missing a javadoc comment
方法前面缺少javadoc註釋
4.Expected @throws tag for “Exception”
在註釋中希望有@throws的說明
5.“.” Is preceeded with whitespace “.”
前面不能有空格
6.“.” Is followed by whitespace“.”
後面不能有空格
7.“=” is not preceeded with whitespace
“=” 前面缺少空格
8.“=” is not followed with whitespace
“=” 後面缺少空格
9.“}” should be on the same line
“}” 應該與下條語句位於同一行
10.Unused @param tag for “unused”
沒有引數“unused”,不需註釋
11.Variable “CA” missing javadoc
變數“CA”缺少javadoc註釋
12.Line longer than 80characters
行長度超過80
13.Line contains a tab character
行含有”tab” 字元
14.Redundant “Public” modifier
冗餘的“public” modifier
15.Final modifier out of order with the JSL
suggestionFinal modifier的順序錯誤
16.Avoid using the “.*” form of import
Import格式避免使用“.*”
17.Redundant import from the same package
從同一個包中Import內容
18.Unused import-java.util.list
Import進來的java.util.list沒有被使用
19.Duplicate import to line 13
重複Import同一個內容
20.Import from illegal package
從非法包中 Import內容
21.“while” construct must use “{}”
“while” 語句缺少“{}”
22.Variable “sTest1” must be private and have accessor method
變數“sTest1”應該是private的,並且有呼叫它的方法
23.Variable “ABC” must match pattern “^[a-z][a-zA-Z0-9]*$”
變數“ABC”不符合命名規則“^[a-z][a-zA-Z0-9]*$”
24.“(” is followed by whitespace
“(” 後面不能有空格
25.“)” is proceeded by whitespace
“)” 前面不能有空格
可以看出CheckStyle檢查出來的問題,大多是編碼規則以及風格上的問題,這是編寫高質量程式碼最基本的。值得注意的是,我們將一些優秀的開原始碼用CheckStyle來檢查也會檢查出不少問題,這不能不說這些開源不優秀,而是每個公司組織有自己的編寫規範度,這個度既可以減少程式設計師的工作量又可以讓程式碼的可讀性合格,但這個度不一樣符合CheckStyle的完整標準。所以我們一般使用CheckStyle都不會用他的預設標準,而是透過配置,制定適合自己的編碼規則。
自定義CheckStyle規則:
開啟CheckStyle配置,新建一個配置,選擇外部配置檔案。在這之前最好匯出一個eclipse自帶的checkstyle配置檔案(sun_checks.xml),然後重新命名作為一個外部的配置導進去,這麼做的目的是匯入之後可以修改相應的配置,達到自定義配置的目的(因為eclipse自帶的配置是加鎖的,不能修改)。匯入之後,點選右邊的“Configure”進行編輯。
先去掉缺少package-info.java檔案的提示
再將第一句註釋要以“.”結尾這個規則去掉,雙擊“Style javadoc”,將視窗內“checkFirstSentence”勾選去掉。
對於實體類,屬性有了註釋,get set方法也不需要註釋了,雙擊“Method javadoc”將allowMissingPropertyJavadoc勾選中。
“getId不是繼承的方法,必須指定abstract,final或空”,如果你懶得在方法上加“final”,這條規則也可以去掉。
如果你不想每一個引數都加“final”,還需要把引數的final規則去掉:
另外還有一個錯誤“'id' hides a field.”,原因是方法的引數和類裡面定義的域重名了,但使用eclipse生成的get set方法都會這樣,所以可以忽略此項。
至此我們再使用checkstyle檢查一篇,發現僅剩下屬性缺少註釋這個警告。
對每個屬性加上java doc註釋,所有問題都清除了。以此類推,解決checkstyle問題的方法就是:1、按規則解決程式碼問題;2、如果覺得這個問題對你的專案質量影響不大,則可以忽略它。
程式碼重複(PMD的CPD的使用)
對於多人開發的專案,難以避免出現重複程式碼的問題,儘管我們儘量對共用的程式碼進行了封裝,但隨著需求的增加、人員技術水平差異、溝通不足等原因,重複程式碼會越來越多。這不僅嚴重影響程式碼質量,也無形中增加了程式碼量。
注:精簡的程式和高複用度的程式碼是我們一直追求的目標。
PMD的CPD工具就是為檢查重複程式碼而生的。右鍵專案--->PMD---->Find Suspect Cut and Paste,執行重複程式碼檢查:
檢查出來的重複程式碼,可以雙擊檢視。然後根據業務邏輯以及程式碼特徵,決定要不要做封裝、怎麼封裝。
程式碼覆蓋率(Eclemma的使用)
一份質量合格的程式碼,不僅包含功能程式本身也包含了對應的測試程式碼,Eclemma外掛可以用來統計測試程式碼覆蓋整體程式碼中的比率,以此來評估程式碼的功能性和穩定性。
使用Junit編寫好測試用例之後,右鍵Coverage As--->Junit Test,執行測試用例,Eclemma會統計出相關的程式碼覆蓋率:
根據這個結果,你可以看出自己編寫的測試用例覆蓋到了那些程式碼,而沒有覆蓋到的程式碼,則有可能成為程式碼質量的盲區。
依賴項分析(JDepend的使用)
隨著程式業務邏輯的增加,程式碼的依賴關係也變的越來越複雜,JDepend外掛可以統計包和類的依賴關係,分析出程式的穩定性、抽象性和是否存在迴圈依賴的問題。右鍵包--->Run JDepend Analysis:
看一下這幾項指標:
CC(Number of Classes)
被分析package的具體和抽象類(和介面)的數量,用於衡量package的可擴充套件性。如果一個類中實現了其他類,如實現了監聽類,則監聽類的數目也記錄在此。
AC(Abstract classes)
抽象類和介面的數量。
Ca(Afferent Couplings)
依賴於被分析package的其他package的數量,用於衡量pacakge的職責。即有多少包呼叫了它。
Ce(Efferent Couplings)
被分析package的類所依賴的其他package的數量,用於衡量package的獨立性。即它呼叫了多少其他包。
A(Abstractness)
被分析package中的抽象類和介面與所在package所有類數量的比例,取值範圍為0-1。
I(Instability)
I=Ce/(Ce+Ca),用於衡量package的不穩定性,取值範圍為0-1。I=0表示最穩定,I=1表示最不穩定。即如果這個類不呼叫任何其他包,則它是最穩定的。
D(Distance)
被分析package和理想曲線A+I=1的垂直距離,用於衡量package在穩定性和抽象性之間的平衡。理想的package要麼完全是抽象類和穩定(x=0,y=1),要麼完全是具體類和不穩定(x=1,y=0)。取值範圍為0-1,D=0表示完全符合理想標準,D=1表示package最大程度地偏離了理想標準。即你的包要麼全是介面,不呼叫任何其他包(完全是抽象類和穩定),要麼是具體類,不被任何其他包呼叫。
Cycle
迴圈依賴的數量。
有個這個報告我們就可以有針對性的對程式碼進行設計和重構。
複雜度分析(Metrics的使用)
對於閱讀程式碼的人來說,越簡單的程式碼越好理解和維護,如果你的程式碼閱讀起來很費勁或者你自己過段時間後再來看都看不懂,你就得想辦法解決下程式碼的複雜度問題了。Metrics外掛可以幫你做到這點。
首先在Java透檢視下右鍵一個專案---->Properties,選擇Metrics,勾選Enble Metrics。
然後Window--->Show View---->Other---->Metrics View
開啟Metrics檢視,點選右上角執行圖示,即可得到複雜度分析的結果:
可以根據複雜度指標,對自己的程式進行最佳化。
小結
本文介紹了和java程式碼質量相關的5個方面問題,並介紹對應eclipse外掛的用法和作用。在我們實際開發中,儘量根據自己公司和團隊的情況來制定一些檢查規則,來提高程式碼質量。並且在大多數情況下,會有兩個檢查環節,即本地檢查和持續整合環境的檢查,我們常用的Hudson就可以整合很多外掛。
參考資料:
追求程式碼質量: 軟體架構的程式碼質量http://www.ibm.com/developerworks/cn/java/j-cq04256/
JDepend
http://www.clarkware.com/software/JDepend.html
PMD
http://pmd.sourceforge.net/
CheckStyle
http://sourceforge.net/projects/eclipse-cs/?source=directory
Eclemma
http://www.eclemma.org/
Metrics
http://metrics.codahale.com/