前端代码质量——圈复杂度原理和实践

  

写程序时时刻记着,这个将来要维护你写的程序的人是一个有严重倾向,并且知道你住在哪里的精神变态者。

  
      <李>导读
    你们是否也有过下面的想法?李   
  

重构一个项目还不如新开发一个项目…
这代码是谁写的,我真想…
你们的项目中是否也存在下面的问题?

  

单个项目也越来越庞大,团队成员代码风格不一致,无法对整体的代码质量做全面的掌控
没有一个准确的标准去衡量代码结构复杂的程度,无法量化一个项目的代码质量
重构代码后无法立即量化重构后代码质量是否提升
针对上面的问题,本文的主角圈复杂度重磅登场,本文将从圈复杂度原理出发,介绍圈复杂度的计算方法,如何降低代码的圈复杂度,如何获取圈复杂度,以及圈复杂度在公司项目的实践应用。

     <李>圈复杂度
2.1定义
圈复杂度(圈复杂度)是一种代码复杂度的衡量标准,也称为条件复杂度或循环复杂度,它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立现行路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。简称CC。其符号为VG或是M。      

圈复杂度在1976年由托马斯·j·麦凯布老提出。

  

圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难于测试和维护。程序的可能错误和高的圈复杂度有着很大关系。

  

2.2衡量标准
代码复杂度低,代码不一定好,但代码复杂度高,代码一定不好。

  

圈复杂度代码状况可测性维护成本
1 - 10清晰,结构化高低
10 - 20复杂中中
20 - 30个非常复杂低高

  
  

30不可读不可测非常高

     <李>计算方法
3.1控制流程图
控制流程图,是一个过程或程序的抽象表现,是用在编译器中的一个抽象数据结构,由编译器在内部维护,代表了一个程序执行过程中会遍历到的所有路径。它用图的形式表示一个过程内所有基本块执行的可能流向,也能反映一个过程的实时执行过程。         

下面是一些常见的控制流程:

  

3.2节点判定法
有一个简单的计算方法,圈复杂度实际上就是等于判定节点的数量再加上1。向上面提到的:如果其他,开关的情况下,对循环,三元运算符等等,都属于一个判定节点,例如下面的代码:

  

函数testComplexity (参数) {
=1让结果;
如果参数比;——0){
结果;
}
(让我=0;我& lt;10;我+ +){
结果+=math . random ();
}
开关(方法(结果)){
案例1:20 +=
结果;
打破;
案例2:30 +=
结果;
打破;
默认值:10 +=
结果;
打破;
}
在返回结果;20吗?结果:结果;
}
复制代码
上面的代码中一共有1个如果语句,一个为循环,两个案例语句,一个三元运算符,所以代码复杂度为1 + 2 + 1 + 1 + 1=6。另外,需要注意的是| |和,,语句也会被算作一个判定节点,例如下面代码的代码复杂为3:

  

函数testComplexity (参数) {
=1让结果;
如果参数比;0,,param & lt;——10){
结果;
}
返回结果;
}
复制代码
3.3点边计算法
M=E ?N + 2 P
复制代码
E:控制流图中边的数量
N:控制流图中的节点数量
P:独立组件的数目
前两个,边和节点都是数据结构图中最基本的概念:

  

p代表图中独立组件的数目,独立组件是什么意思呢?来看看下面两个图,左侧为连通图,右侧为非连通图:

  

连通图:对于图中任意两个顶点都是连通的

  

一个连通图即为图中的一个独立组件,所以左侧图中独立组件的数目为1,右侧则有两个独立组件。

  

对于我们的代码转化而来的控制流程图,正常情况下所有节点都应该是连通的,除非你在某些节点之前执行了回报,显然这样的代码是错误的,所以每个程序流程图的独立组件的数目都为1,所以上面的公式还可以简化为M=E ?N + 2 .

     <李>降低代码的圈复杂度
我们可以通过一些代码重构手段来降低代码的圈复杂度。      

重构需谨慎,示例代码仅仅代表一种思想,实际代码要远远比示例代码复杂的多。

  

4.1抽象配置
通过抽象配置将复杂的逻辑判断进行简化。例如下面的代码,根据用户的选择项执行相应的操作,重构后降低了代码复杂度,并且如果之后有新的选项,直接加入配置即可,而不需要再去深入代码逻辑中进行改动:

前端代码质量——圈复杂度原理和实践