什么是圈复杂度?

Posted

技术标签:

【中文标题】什么是圈复杂度?【英文标题】:What is Cyclomatic Complexity? 【发布时间】:2010-10-29 00:55:57 【问题描述】:

我不时看到的一个术语是“循环复杂性”。在 SO 上,我看到了一些关于“如何计算语言 X 的 CC”或“我如何用最少的 CC 做 Y”的问题,但我不确定我是否真的明白它是什么。

在NDepend Website 上,我看到一个解释,基本上是说“方法中的决策数量。每个 if、for、&& 等都会在 CC“分数”上加 1)。真的是这样吗?如果是的,为什么这很糟糕?我可以看到人们可能希望将 if 语句的数量保持在相当低的水平以使代码易于理解,但这真的是一切吗?

还是有更深层次的概念?

【问题讨论】:

【参考方案1】:

我不知道更深层次的概念。我相信它通常是在可维护性指数的背景下考虑的。特定方法中的分支越多,维护该方法操作的心智模型就越困难(通常)。

具有较高圈复杂度的方法也更难以在单元测试中获得完整的代码覆盖率。 (感谢Mark W!)

当然,这会带来可维护性的所有其他方面。错误/回归/等等的可能性。不过,核心概念非常简单。

【讨论】:

另外,单元测试和获得完整的代码覆盖率越难。 对,因为他们说在任何特定时刻,你只能在良心头脑中保留一些东西。 方法的圈复杂度也表示实现该方法的 100% 代码覆盖率所需的单元测试用例的数量。 'The more branches there are within a particular method'... 你的意思是更多的 IF-Else 语句?【参考方案2】:

圈复杂度衡量您必须执行具有不同参数的代码块以执行通过该块的每条路径的次数。更高的计数是不好的,因为它增加了逻辑错误逃脱测试策略的机会。

【讨论】:

【参考方案3】:
Cyclocmatic complexity = Number of decision points + 1

决策点可能是您的条件语句,例如 if、if ... else、switch、for 循环、while 循环等。

下表描述了应用程序的类型。

圈复杂度为 1 – 10  被视为正常 应用

圈复杂度在于 11 – 20  中等应用

圈复杂度在于 21 – 50  风险应用

圈复杂度超过 50  应用不稳定

【讨论】:

“循环复杂度 = 决策点数 + 1” 对于我尝试过的所有情况,它似乎都成立。我只有一个问题:当我们只需要decision_points+1 时,为什么我们还要为流程图和公式而烦恼? (无论如何,感谢这个极其简单的方法!)【参考方案4】:

***可能是你的朋友:Definition of cyclomatic complexity

基本上,您必须将您的程序想象为control flow graph,然后

复杂度是 (...) 定义为:

M = E − N + 2P

在哪里

M = 圈复杂度, E = 图的边数 N = 图的节点数 P = 连接组件的数量

CC 是一个概念,它试图捕捉您的程序的复杂程度以及用单个整数对其进行测试的难度。

【讨论】:

【参考方案5】:

是的,就是这样。您的代码可以采用的执行路径越多,必须测试的东西就越多,出错的可能性就越高。

【讨论】:

【参考方案6】:

我听到的另一个有趣的观点:

代码中缩进最大的地方应该有最高的 CC。这些通常是确保测试覆盖率的最重要领域,因为预计它们将更难阅读/维护。正如其他答案所指出的,这些也是更难确保覆盖的代码区域。

【讨论】:

【参考方案7】:

圈复杂度真的只是一个可怕的流行语。事实上,它是软件开发中用于指出更复杂的代码部分(更可能是错误的,因此必须非常仔细和彻底地测试)的代码复杂性的度量。您可以使用 E-N+2P 公式计算它,但我建议您通过插件自动计算它。我听说过一个经验法则,即您应该努力将 CC 保持在 5 以下,以保持代码的良好可读性和可维护性。

我最近在我的 Java 项目中尝试了 Eclipse Metrics Plugin,它有一个非常简洁的帮助文件,它当然会与你的常规 Eclipse 帮助集成,你可以阅读更多关于各种复杂性度量的定义和改进代码的提示和技巧。

【讨论】:

【参考方案8】:

就是这样,这个想法是,具有低 CC 的方法具有更少的分叉、循环等,这些都使方法更加复杂。想象一下,使用分析器查看 500,000 行代码,并看到一些方法的 CC 量级更高。这让您可以专注于重构这些方法以更好地理解(高 CC 也有高错误率也很常见)

【讨论】:

【参考方案9】:

例程(循环、开关、if 等)中的每个决策点本质上归结为等效的 if 语句。对于每个 if,您有 2 个可以采用的代码路径。因此,第一个分支有 2 个代码路径,第二个分支有 4 个可能的路径,第三个分支有 8 个,依此类推。至少有 2**N 个代码路径,其中 N 是分支数。

这使得理解代码的行为并在 N 超过某个小数时对其进行测试变得困难。

【讨论】:

【参考方案10】:

到目前为止提供的答案并未提及软件质量与圈复杂度的相关性。研究表明,具有较低的圈复杂度度量应该有助于开发更高质量的软件。它可以帮助提高可读性、可维护性和可移植性的软件质量属性。一般来说,应该尝试获得 5-10 之间的圈复杂度度量。

使用圈复杂度等指标的原因之一是,一般而言,人类只能在大脑中同时跟踪大约 7(正负 2)条信息。因此,如果您的软件过于复杂且具有多个决策路径,那么您不太可能能够可视化您的软件的行为方式(即,它将具有较高的圈复杂度度量)。这很可能会导致开发错误或漏洞百出的软件。可以在here 和Wikipedia 上找到更多信息。

【讨论】:

【参考方案11】:

使用控制流图计算圈复杂度。通过程序源代码的线性独立路径的数量度量称为循环复杂度(if/if else/for/while)

【讨论】:

【参考方案12】:

圈复杂度基本上是一种度量,用于确定需要更多注意以实现可维护性的代码区域。它基本上是重构的输入。 在避免深度嵌套循环、条件等方面,它肯定给出了代码改进领域的指示。

【讨论】:

【参考方案13】:

就是这样。但是,“case”或“switch”语句的每个分支都倾向于计为 1。实际上,这意味着 CC 讨厌 case 语句以及任何需要它们的代码(命令处理器、状态机、等)。

【讨论】:

@TetsujinnoOni - 五月 是的。问题是我的典型命令处理器是从一些外部源读取命令,所以我不能让编译器将数据项放在它想要的任何地方,就像它必须为动态多态类一样。【参考方案14】:

考虑你的函数的control flow graph,从出口到入口有一条额外的边。圈复杂度是我们可以在不将图分成两部分的情况下进行的最大切割数。

例如:

function F:
    if condition1:
       ...
    else:
       ...
    if condition2:
       ...
    else:
       ...

Control Flow Graph

您可能可以直观地看到为什么链接图的圈复杂度为 3。

【讨论】:

你能解释一下你在上图中是如何以及在哪里进行切割的吗?【参考方案15】:

圈复杂度衡量软件单元的复杂程度。它衡量程序使用条件逻辑构造(If、while、for、switch 和 case 等)可能遵循的不同路径的数量。如果您想了解有关计算的更多信息,这里有一个精彩的 youtube 视频,您可以观看 https://www.youtube.com/watch?v=PlCGomvu-NM

在设计测试用例时很重要,因为它揭示了程序可以采用的不同路径或场景。 “为了具有良好的可测试性和可维护性,McCabe 建议 任何程序模块的圈复杂度都不应超过 10"(Marsic,2012,第 232 页)。

参考: Marsic., I.(2012 年 9 月)。 软件工程。罗格斯大学。取自 www.ece.rutgers.edu/~marsic/books/SE/book-SE_marsic.pdf

【讨论】:

以上是关于什么是圈复杂度?的主要内容,如果未能解决你的问题,请参考以下文章

什么是Cyclomatic Complexity(圈复杂度)?

圈复杂度 Cyclomatic complexity 介绍

圈复杂度 Cyclomatic complexity 介绍

圈复杂度 Cyclomatic complexity 介绍

圈复杂度

软件测试圈复杂度