【閱讀筆記】軟體構築美學(05)軟體度量與程式碼分析

定義軟體度量與程式碼分析。介紹常見的度量指標。自動產生度量數據。

書名:軟體構築美學

作者:Kyle Baley,Donald Belcham

譯者:蔡煥麟,張簡才祿

發行公司:悅知文化,精誠資訊股份有限公司

度量不是為了直接處理特定問題。

它們的主要功用,是讓你能夠發現由其他現象所導致的問題。

 

何謂軟體度量與程式碼分析?

軟體度量就是一些測量項目,像是程式碼行數、類別總數、繼承深度等等。

運用這些度量來分析你的程式碼。

程式碼分析分為兩種:靜態動態

靜態程式碼分析

在程式未執行的狀態下,對程式碼進行分析。

常見的有:程式碼行數類別耦合度,以及循環複雜度

動態程式碼分析

程式執行時所進行的分析。

常見的有:程式碼涵蓋範圍,應用程式執行期間所走過的程式碼的比例

另一種:分析記憶體的使用率,以及檢查記憶體洩漏的問題。

為什麼需要程式碼度量?

答案是:你並不需要,或者你也許不需要。

即時沒有程式碼分析,你的專案也可能活得好好的。

但可以讓你有條理的整理程式碼

比如說,藉由分析統計的結果,你可以看到哪些類別的耦合度最高,然後也許你會實作依賴注入,來降低耦合度

利用瑕疵報告來分析程式碼,從趨勢中研判哪些地方需要重構

用靜態程式碼分析來強制架構方面的設計限制。

 

常用的度量指標

程式碼涵蓋範圍(code coverage) 循環複雜度(cyclomatic complexity) 類別耦合度(class coupling)

程式碼涵蓋範圍

監控程式碼執行的過程,顯示剛才有執行到(或有涵蓋到)的程式碼,以及最重要的是哪些程式碼沒有執行到

程式碼涵蓋範圍的真正威力所在,是當它和單元測試整合測試一起搭配運用的時候。

在測試結束時,程式碼涵蓋工具會自動產生一份報告。

單單了解程式碼的執行狀況,就能夠讓你提高對程式碼的信心

循環複雜度

用來測量程式碼的複雜度,讓我們了解應用程式內部結構多複雜。

像 if 敘述、for 迴圈、switch 敘述,和邏輯運算子等等,都會增加程式的循環複雜度。

複雜度的值不重要,重點在於你對測量數據的解釋必須維持一致,並且訂出一個合理的門檻值。

高循環複雜度可能代表程式碼比較難維護,而維護又意味著必須修改程式碼

類別耦合度

代表類別之間的耦合程度。

傳入耦合度:有多少類別依賴我?

傳出耦合度:我依賴多少類別?

高耦合度代表程式碼不易修改,當你要修改程式碼時,都會引發一連串的修改,稱為漣漪效應

為了提高程式碼的可維護性,必須盡量減少漣漪效應產生的衝擊。

內聚力

與耦合度有關的度量是內聚力,類別有很高的內聚力,即表示其功能與責任是緊密結合的

有大量低內聚力的類別,通常都比較難維護

高內聚力雖然是好事,但並不代表你就應該丟掉所有的 HelperMethods 類別,或將你的網路服務拆成多個類別。

與主序帶之距離(distance from main sequence)

你的組件離理想的主序帶有多遠?

抽象度與不穩地度的組合。

抽象度指的是程式的所有類別內,有多少是抽象類別。

抽象度(A):某個組件沒有任何抽象類別或介面,則 A = 0,若完成沒有具象類別,則 A = 1。0(具象)1(抽象)

耦合度(I):耦合度 = 傳出耦合度 / (傳出耦合度 + 傳入耦合度)。0(穩定)1(不穩定)。

理想組件的抽象度與不穩定度的總和為 1 。我們說他在抽象與不穩定之間取得平衡。

A + I = 1 所涵蓋的區域即所謂的主序帶。

痛苦地帶(zone of pain)與無用地帶(zone of uselessness)

無用地帶:代表組件是抽象且不穩定的。也就是說,組件中有需多抽象類別或介面,而且它們依賴外部型別的程度非常高。

痛苦地帶:代表組件是具象且穩定的。也就是說,組件包含許多具象類別,而且有很多外部組建依賴它們,非常缺乏彈性。

繼承深度

代表某個類別的繼承階層有多深、或有幾層。

常見的名稱為『繼承樹的深度』(depth of inheritance tree)。

類別的繼承深度越深,通常就越難維護

可維護性指數

直覺之處在於,它是用來測量程式碼有多容易維護的指標。

迷人之處在於,他能夠透過量化方法來將原來為質性的東西以數字呈現。

MI = 171 -(5.2 x ln(HV 程式碼複雜度))-(0.23 x CycCom 循環複雜度)-(16.2 x ln(LOC 程式碼行數))。

此度量的參考價值已經不高。

 

 成為統計的奴隸

程式碼度量本身也有一些陷阱。

極端狀況:開發團隊太在意這些統計數字,只依數據行事,而不管對專案有沒有幫助

舉例來說:程式碼涵蓋範圍達 80% 建置才是成功。

您的專案為 81%,但經過重構後,刪除不必要的程式碼,變為 79%

但你的單元測試已經涵蓋100%,但你的建置是失敗的

有三種方法可以處理此問題

  • 把剛剛的重構復原,讓他回原先的 80%
  • 修改測試程式,直到程式碼涵蓋範圍到 80%
  • 降低程式碼涵蓋範圍的基準

您應該選擇第三個方法。

不要讓自動化建置程序依賴任何統計數字,無論它是程式碼涵蓋範圍、類別耦合度,還是其他度量指標。

為了避免開發人員太過專注於程式碼的度量指標,而忘了真正該注意的,其實是程式碼本身。

軟體度量的用途如同曳光彈,是用來指引,而非規範

 

實作統計分析

自動計算程式碼涵蓋範圍

Step 1: 編譯應用程式
Step 2: 編譯測試專案
Step 3: 把單元測試的測試組件當作參數餵給程式碼涵蓋範圍工具

度量指標與CI

程式碼涵蓋範圍整合至你的 CI 程序,但請別再將其他程式碼度量指標也一併整合至 CI

你不會想要在每次簽入時,都產生一次度量結果,因為產生統計資料需要花費很多時間

比較好的做法,用另一個獨立的自動化程序,依照週期,例如每週執一次等等。

重點是讓每次產生的統計資料跟上一次的結果有些明顯的差異,以便觀察其中的變化

 

其他自動執行的工作

以下是一些可以考慮自動執行的動作(括號是建議使用的工具)

  • 從 XML 註解產生說明文件( Sandcastle 或 Docu)
  • 強制寫碼規範( FxCop 或 StyleCop )
  • 檢查重複的程式碼( Simian-Similarity Analyser )
  • 程式碼產生器( CodeSmith 或 MyGeneration)
  • 資料轉移、測試資料庫的建立( SQL Data Compare/ SQL Packager / SQL script 

只要能夠減少人工的操作錯誤,讓你專注於提高生產力,都值得考慮將它們納入自動化程序

 

總結

當您意識到『我為什麼要一直做這件事呀?』請問再自己『為什麼我們不把它自動化呢?』

程式碼度量,它們幫你挑出問題,剩下的工作就是找出正確的處理方法了。

目的都是幫您改善軟體的可維護性。