程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 追求代碼質量 - 馴服復雜的冗長代碼

追求代碼質量 - 馴服復雜的冗長代碼

編輯:關於JAVA

我毫不慚愧地承認,在看到復雜的代碼塊時,我也會感到恐懼和心裡發毛。事實上,我敢說您在遇到大量方法和亂七八糟四處蔓延的類時,也會 有些心裡 發毛的。不能說在這些情況下尋求退路的人不是完人,這只是優秀開發人員的一 種本能。過於復雜的代碼難以測試和維護,這通常還意味著更高的出錯率。

我在 本系列前面的文章 中已經解釋了圈復雜性,它是令人討厭的代碼的一 種先兆。具有高圈復雜度值的測試方法幾乎總是把事情弄得一團糟,無法輕易收 場。上一個月,我向您展示了如何使用 Extract Method 模式重構您的代碼,從 而將您帶出迷宮。降低方法的復雜度可以使代碼更易於測試和維護,如圖 1 所 示:

圖 1. 降低復雜度可以使代碼更易於維護和測試

不過,圈復雜性並不是確定高風險代碼的惟一復雜性度量。您還可以利用類 長度、方法長度和內部類耦合。這些度量之間存在著錯綜復雜的關聯,但是很容 易發現這些關聯。這個月,我將解釋它們為什麼那麼重要,以及如何使用 PMD 和 JavaNCSS 跟蹤它們。

代碼太多了!

了解簡單代碼和流暢代碼之間的區別非常重要。簡單代碼不必過分簡單或易 於編寫,只需易於理解 即可。您可以使用 C++ 編寫簡單代碼,就像使用 Visual Basic 編寫它們那樣。不過,用任何語言反簡化 代碼的最快方式都是一 次編寫大量的代碼。

考慮一下如何將此規則應用於方法和類。大多數人對記住信用卡號感到頭疼 的一個簡單原因是,我們一次只能管理 7(±2) 片數據。了解了這一點,就會明 白過多的條件會給以後帶來麻煩,使測試和維護變得很困難。相同的原理也可以 應用於邏輯塊。

所有給定代碼主體通常包含已分組的語句,它們擁有共同的目標,比如創建 一個集合,將數據項添加到該集合中。但是,在一個長方法(long method)中 分組數量眾多的邏輯塊可能會讓人很快忘記該方法的總體意圖,因為很少有人可 以有效處理這樣一個大的數據集。恰恰是這個缺點帶來了代碼基中的維護問題。冗長的方法是缺陷的避風港,因為很少有人可以有效地分析它們。長方法不僅完 成太多的工作,也需要人們費很大的勁去理解!

就像長方法會讓開發人 員討厭一樣,長類(long class)也會令開發人員討厭。相同的討論也可以應用 於總體代碼,冗長的類可能會做太多的工作,並承擔太多的責任。

什麼 樣才算太長?

當然了,長方法或類的劃分有點主觀。有一個很有幫助的 經驗法則,您可以說非代碼注釋行超過 100 行的方法是長方法。不過,實際的 數值是根據談論的人而變化的。就我而言,截止點(cutoff point)大約是 50 行代碼,但有些開發人員會說,如果某一方法需要您向下滾動整整一天才能看完 ,那麼該方法太長了。截止點的定義取決於您自己。

類似地,您必須有 自己的確定正確類大小的良好判斷。許多人所提倡的一條經驗法則是,類的代碼 行超過 1,000 行就可以說該類太長了。而另一些人則認為最好不要超過 500 行 代碼。

內部類耦合

對於一對象與其他對象之間的關系,復雜模式 會不斷重復其自身。對於導入許多外部依賴項或者擁有許多 public 方法的類, 不但理解起來有些困難,而且所帶來的責任重擔的增加也會導致某種脆弱。

我將從依賴項開始。如果某一對象導入的外部類超過 80 個(不包括普 通的 Java™ 系統庫),那麼就可以說該類具有高度輸出耦合,這意味著 更改導入的類可能會影響該類本身。在最糟糕的情況下,如果導入的是具體的類 ,並且它們的行為發生更改,那麼執行導入的類可能會中斷!

觀察對象導入的數量就很容易預測脆弱性,但如果使用 .* 符號(例如 com.acme.user.*)導入整個包,則很可能產生誤導。為了更精確起見,可能需 要注意對象所擁有的惟一類型 的數量(該數量可通過解析代碼獲得 —— 不是 import 語句)。如果應用程序的包結構大致上以某種在少數包中包含許多類的 方式設計,則惟一類型度量(types metric)可能很有幫助。

包含許多 public 方法的類也有許多導入。這些類通常會成為代碼基的中心 ,就像 Facades 或工具類那樣。因為存在這種責任(通過大量 public 方法導 出),所以它們具有高度的輸入耦合,也會導致反向的脆弱性。如果這些類中的 任何一個發生更改,各種表面上不相關的應用程序部分可能 發生中斷。

復雜性是如何產生關聯的

到目前為止,所給出的模式都在暗示臃腫的代碼(長方法、太多的 public 方法、過多的條件和導入,等等)將影響可讀性、可測試性和可維護性。因為該 模式用各種度量來重復自己,所以所有這些因素都會導致相互關聯。例如,長方 法通常得容忍高圈復雜度值,如圖 2 所示:

圖 2. 長方法與圈復雜性相互關聯

不過,相關性並不止於此。具有過多導入的類會有許多惟一類型。這些類通 常非常大。而大型的類通常擁有長方法,長方法又常常有很高的圈復雜度值。圖 3 展示了復雜性度量是如何相關的:

圖 3. 復雜性度量是如何相關的

PMD 和 JavaNCSS

少量的繁瑣代碼可用 PMD 和(更小范圍的)JavaNCSS 輕松處理,很容易結 合使用這兩種工具,以構建諸如 Ant 和 Maven 之類的平台。

可以將 PMD 看作是基於規則的引擎,它分析源代碼並報告正被違反的某一規 則的所有實例。PMD 目前定義了大約 200 個規則,其中一些特定規則是針對方 法長度、類長度和惟一類型的,還有一些用於計算 public 方法。您還可以定義 定制規則和修改現有規則(例如,為了反映域的需求)。

定制 PMD

例如,我將使用 PMD 的經過恰當命名的 ExcessiveMethodLength 規則來發 現長方法。此規則的默認長度阈值是 100(這意味著如果某個所掃描方法的長度 超過 100 行,則 PMD 會報告出現一個違規),但是如果您喜歡的話,可以降低 該阈值。

PMD 規則可以定義屬性,通過站在 PMD 開發團隊的角度很好地進行預見,您 可以通過使用規則集文件在運行的時候覆蓋這些屬性。要將 ExcessiveMethodLength 規則的默認值從 100 降低到 50,可以將 properties 元素添加到 rule 定義中並引用屬性的名稱。在清單 1 中,我將一個名為 minimum 的屬性添加到了 PMD rule 定義中:

清單 1. 定制 ExcessiveMethodLength 規則

<rule  ref="rulesets/codesize.xml/ExcessiveMethodLength">
  <properties>
  <property name="minimum" value="50"/>
  </properties>
</rule>

用 Ant 工具調用帶有定制規則集文件的 PMD 需要通過 PMD 任務的 rulesetfiles 屬性提供一條到該定制文件的路徑,如清單 2 中所示:

清單 2. 引用定制規則集文件

<pmd  rulesetfiles="./tools/pmd/rules-pmd.xml">
  <formatter type="xml"  toFile="${defaulttargetdir}/pmd_report.xml"/>
  <formatter type="html"  toFile="${defaulttargetdir}/pmd_report.html"/>
  <fileset dir="./src/java">
  <include name="**/*.java"/>
  </fileset>
</pmd>

PMD 報告由源文件導致的違規,正如您在圖 4 中可以看到的,在本例中,只 有少數幾個方法的源代碼行超過了 50 行:

圖 4. PMD Ant 報告的示例

對於長類,PMD 有 ExcessiveClassLength 規則,長類的默認值為 1,000 行 代碼。對於 ExcessiveMethodLength 規則,很容易使用更適合的值覆蓋默認值 。此外,PMD 還有一個用來計算惟一類型的規則,即 CouplingBetweenObjects 規則。要計算導入,請參見 ExcessiveImports 規則。這兩個規則都是可配置的 。

使用 JavaNCSS 測量代碼是否冗長

PMD 定義了用來分析源代碼的特定規則,與 PMD 相對,JavaNCSS 分析代碼 基並報告所有一切 與代碼長度相關的事項,包括類大小、方法大小和類中找到 的方法數量。對於 JavaNCSS,阈值無關緊要,它計算所找到的每個文件並報告 值,而不管 大小如何。盡管與 PMD 相比較而言,這類數據看起來似乎有些呆板 (並且可能有點羅嗦!),但它有它存在的道理。

通過報告所有文件大小,JavaNCSS 使理解相關值成為可能,而 PMD 常常難 以做到這一點。例如,PMD 只報告違規的文件,這意味著只理解部分代碼基的數 據,而 JavaNCSS 在上下文中提供了代碼長度數據,如圖 5 所示:

圖 5. JavaNCSS Ant 報告的示例

結束語

綠地開發(greenfield development)是指開發團隊首先開發一個空白的 IDE 控制台,並用漂亮、簡潔的代碼填充它,這只是軟件應用程序生存期中一個 非常小 的片段。如今,很多跨國企業仍然在運行基於 COBOL 的應用程序,從開 發人員的角度看,這意味著要與您不認識的人在很久以前編寫的代碼作斗爭。

在遇到這樣的難題時,通常會令人感到非常厭惡,您只能在連續幾天的時間 裡聲稱自己生病了進行逃避。隨後的某一時刻,您必須面對大量代碼塊並將它們 搞定。使用針對類長度、方法長度和內部類耦合的復雜性度量(即對象導入和惟 一類型)是理解您所面臨的困難的第一步。從一些與類大小和方法大小有關的經 驗法則開始,然後使用諸如 PMD 和 JavaNCSS 之類的工具詳細介紹。

當第一次在遺留代碼基上使用復雜性度量時,您將了解到一個龐大的數量, 但不要就此停住腳步。通過繼續監視復雜性度量,您可以作出更明智的決定,並 在不斷擴展和維護代碼時降低風險。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved