圈復(fù)雜度(Cyclomatic complexity)也稱為條件復(fù)雜度或循環(huán)復(fù)雜度,是一種軟件度量,是由Thomas J. McCabe, Sr. 在 1976 年提出,用來表示程序的復(fù)雜度,其符號為 VG 或是 M。圈復(fù)雜度是對源代碼中線性獨立路徑數(shù)的定量測量。
圈復(fù)雜度使用的程序的控制流圖來計算:在圖中的節(jié)點對應(yīng)于程序中一組不可分割的命令[代碼行],有向邊連接兩個可連續(xù)執(zhí)行的節(jié)點;[可連續(xù)執(zhí)行的兩個節(jié)點:第二個節(jié)點的命令組可能在第一個節(jié)點執(zhí)行后立刻開始執(zhí)行]。圈復(fù)雜度可以應(yīng)用到獨立的功能,模塊,方法或類。
基礎(chǔ)路徑測試:通過測試用例測試程序中的每個線性無關(guān)的獨立路徑;在這種測試策略下,測試用例的數(shù)目將等于該程序的圈復(fù)雜度;
圈復(fù)雜度定義
圈復(fù)雜度度量的是程序中線性獨立路徑的數(shù)量;例如:如果程序中不包含控制、判斷、條件語句(例如 if,swith 等),那么復(fù)雜度就是 1 ;因為整個程序只有一條執(zhí)行路徑;如果程序包含一條IF語句,那么就會有兩條路徑來執(zhí)行完整個程序(IF為 TRUE,IF 為 FALSE),所以這時候的復(fù)雜度就是 2;兩個嵌套的 IF 語句,或者包含兩個判斷條件的一個 IF 語句,復(fù)雜度就是 4;
在數(shù)學(xué)上,一個結(jié)構(gòu)化程序的圈復(fù)雜度通過該程序的控制流圖來定義;控制流圖包含程序的基本塊(圖的節(jié)點),和兩個基本塊之間可執(zhí)行性(圖的邊)。
原理:

上圖:單程序的控制流圖。此程序由紅色的節(jié)點開始運行,然后進(jìn)入循環(huán)(紅色節(jié)點下由三個節(jié)點組成),離開循環(huán)后有條件分支,最后運行藍(lán)色節(jié)點后結(jié)束,此控制流圖中,E = 9, N = 8, P = 1,因此其圈復(fù)雜度為 9 - 8 + (2*1) = 3
數(shù)學(xué)表達(dá)式:
M = E - N + 2P
其中
E 為圖中邊的個數(shù)
N 為圖中節(jié)點的個數(shù)
P 為連接組件的個數(shù)
強連通圖的圈復(fù)雜度定義:要求做完線上功能的先要求線上的功能

上圖:對應(yīng)同一個程序的控制流圖,但多加一個從結(jié)束點到啟始點的邊,因此為強連通的控制流圖,若利用此圖計算圈復(fù)雜度,其公式為 M=E-N+P,而 E = 10、N = 8、P = 1,因此圈復(fù)雜度為 3
另一個計算圈復(fù)雜度的公式用與計算每一個結(jié)束節(jié)點總是連接到啟動節(jié)點的流程控制圖;這種圖稱為強連通的;此時的圈復(fù)雜度就是圖中回路的個數(shù),也稱為第一貝蒂數(shù)[first Betti number]),其公式如下:
M = E - N + P
上式可以視為計算圖中線性獨立回路(回路內(nèi)不包括其他回路)的個數(shù),由于控制流圖增加結(jié)束點到啟始點的邊,因此對應(yīng)一個結(jié)束點至少會有一個回路。
對于單一的程序(或副程序或方法),P 恒為 1。對于單一子程序,該公式可以簡單的表達(dá)為:
M = E - N + 2
圈復(fù)雜度可以適用于同時分析許多程序或副程序的情形(例如針對一個類中的所有方法),此時 P 等于程序的個數(shù),因為每一個程序的圖都是一個獨立的連接組件。若每一個程序都只一個結(jié)束點,P 也可以視為是結(jié)束點的個數(shù)。
McCache 證明了任何只有一個進(jìn)入點和一個技術(shù)點的結(jié)構(gòu)化程序,其圈復(fù)雜度等于程序中決策點(IF,F(xiàn)OR loops)的個數(shù)加 1;
圈復(fù)雜度也可以延伸到多個結(jié)束點的程序,此時的圈復(fù)雜度如下:
π - s + 2
其中
π 是程序中決策點的個數(shù)
s 為結(jié)束點的個數(shù)
圈復(fù)雜度應(yīng)用
限制軟件復(fù)雜度
麥凱布提出圈復(fù)雜度時,其原始目的之一就是希望在軟件開發(fā)過程中就限制其復(fù)雜度。他建議程序設(shè)計者需計算其開發(fā)模塊的復(fù)雜度,若一模塊的圈復(fù)雜度超過 10,需再分區(qū)為更小的模塊。NIST(國家標(biāo)準(zhǔn)技術(shù)研究所)的結(jié)構(gòu)化測試方法論已此作法略作調(diào)整,在一些特定情形下,模塊圈復(fù)雜度上限放寬到 15 會比較合適。此方法論也承認(rèn)有些特殊情形下,模塊的復(fù)雜度需要超過上述的上限,其建議為“模塊的圈復(fù)雜度需在上限范圍以內(nèi),否則需提供書面數(shù)據(jù),說明為何此模塊圈復(fù)雜度有必要超過上限?!?/p>
評估軟件的結(jié)構(gòu)化程度 「structuredness」
Essential complexity (numerical measure of "structuredness")
啟示軟件測試工作
圈復(fù)雜度決定了需要多少個測試用來達(dá)到特定模塊測試覆蓋率要求;
模塊內(nèi)聚性的評估
可以預(yù)期一個復(fù)雜度較高模塊的內(nèi)聚性會比較低,至少不會到功能內(nèi)聚性的程度。一個有高復(fù)雜度及低內(nèi)聚性的模塊中會有許多的決策點,這類的模塊多半運行超過一個明確定義的任務(wù),因此內(nèi)聚性較低。一個 2005 年的研究發(fā)現(xiàn)復(fù)雜度的度量和由專家評估的模塊內(nèi)聚性有高度負(fù)相關(guān),反而針對內(nèi)聚性設(shè)計的度量和專家評估結(jié)果之間的相關(guān)性還比較不明顯[6]。
推測軟件缺陷個數(shù)
許多研究指出一模塊及方法的圈復(fù)雜度和其中的缺陷個數(shù)有相關(guān)性,許多這類研究發(fā)現(xiàn)圈復(fù)雜度和缺陷個數(shù)有高度的正相關(guān):圈復(fù)雜度最高的模塊及方法,其中的缺陷個數(shù)也最多。
不過,有些研究是在控制模塊大小相近的情形下進(jìn)行分析(例如比較二個源代碼行數(shù)相近,但圈復(fù)雜度不同模塊的缺陷個數(shù)),許多這類的研究發(fā)現(xiàn)圈復(fù)雜度和缺陷個數(shù)沒有明顯相關(guān),不過仍有一些研究認(rèn)為在此情形下二者仍有相關(guān)性。有些此領(lǐng)域的研究者認(rèn)為那些研究結(jié)果圈復(fù)雜度和缺陷個數(shù)沒有明顯相關(guān)的研究,其研究方法的有效性可能有問題。
萊斯·哈頓認(rèn)為利用圈復(fù)雜度來預(yù)測缺陷個數(shù),和利用源代碼行數(shù)來預(yù)測缺陷個數(shù)的結(jié)果大致相近。
OneAPM Mobile Insight 以真實用戶體驗為度量標(biāo)準(zhǔn)進(jìn)行 Crash 分析,監(jiān)控網(wǎng)絡(luò)請求及網(wǎng)絡(luò)錯誤,提升用戶留存。訪問 OneAPM 官方網(wǎng)站感受更多應(yīng)用性能優(yōu)化體驗,想閱讀更多技術(shù)文章,請訪問 OneAPM 官方技術(shù)博客。
本文轉(zhuǎn)自 OneAPM 官方博客