概念
圈复杂度(Cyclomatic complexity),也称条件复杂度,是一种代码复杂度的衡量标准。由Thomas J. McCabe于1976年提出,用于表示程序的复杂度。
圈复杂度计算方法
点、边、连通分量计算法
公式:
V(G) = e - n + 2p
e表示控制流图中边(edge)的数量,n(node)表示控制流图中节点的数量,p代表的是连通分量(连通分量的概念可以自行百度,但是在我们常见的程序里,连通分量的值为1)
连通分量:简单来说是加p条边,可以让这个图变成一个强连通图,所谓强连通图是指从任意节点可以到达任意节点的图
节点判定法
简单来说就是程序运行过程中的分岔口,一个分岔口会对应一个节点。当然对于switch 这类一个分岔口,多个节点路径来说,对应的分岔即为判定节点。
常见的判定节点有:
if ... else if ...
while
switch ... case ...
三目运算
&& || 操作
几种常见的控制程序复杂度计算方法
对于程序中的代码而言,如果
| Control | Structure | Cyclomatic Complexity |
|---|---|---|
| Sequence | 暂时无法在飞书文档外展示此内容 | v = 1 - 2 + 2 = 1 |
| If Then Else | 暂时无法在飞书文档外展示此内容 | v = 4 - 4 + 2 = 2 |
| While | 暂时无法在飞书文档外展示此内容 | v = 3 - 3 + 2 = 2 |
| Until | 暂时无法在飞书文档外展示此内容 | v = 3 - 3 + 2 = 2 |
常见的代码场景及其复杂度
If else场景
function testA () {
const a = 1
if (a > 0) {
console.log('大于0')
} else if (a === 0) {
console.log('小于0')
} else {
console.log('等于0')
}
}
对应的图
While场景
function testB () {
let a = 1
while (a < 10) {
a++
}
if (a > 11) {
console.log(a)
}
}
对应的图
圈复杂度及缺陷
圈复杂度不是一个能够让你不会写出BUG的银弹,它只是一个警钟,而这个警钟在你不好好设计代码时会响起。
圈复杂度和软件质量
| 圈复杂度 | 代码状况 | 可测性 | 维护成本 |
|---|---|---|---|
| 1-10 | 清晰、结构化 | 高 | 低 |
| 10-20 | 复杂 | 中 | 中 |
| 20-30 | 非常复杂 | 低 | 高 |
| >30 | 不可读 | 不可测 | 非常高 |
圈复杂度与测试的关系
如果是TDD开发模式,开发者们会更倾向于编写简单的函数以便测试,这样也能够从另一方面驱动开发者编写出圈复杂度低的函数
常见工具
Code Metrics vscode插件(安装该插件并启用后,在每个函数的上面,会提示出对应的圈复杂度值)
引文
更多实践
降低代码的圈复杂度# 概念