Sonar:Cognitive Complexity认知复杂度

Posted 沛沛老爹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sonar:Cognitive Complexity认知复杂度相关的知识,希望对你有一定的参考价值。

背景

在进行代码扫描的时候,发现使用sonar,会提示“Refactor this method to reduce its Cognitive Complexity from 31 to 15 allowed等类似的提示。

翻译成为中文就是:重构方法,以将代码认知复杂度从31降到15。

简单点来理解,就是当前代码的点认知复杂度有点高,对阅读不友好,建议将其代码进行重构。

Cognitive Complexity

Cognitive Complexity翻译成中文就是认知复杂度。

简单来讲就是代码被阅读和理解的复杂程度的一个度量方法,讲代码按照固定的 方式转化成复杂程度的数值。 

认知复杂度数值越高,说明这段代码越复杂!

 记分示例

这里给出一个很有用的例子,可以指出圈复杂度的问题。以下两段方法有着相同的圈复杂度,但是在理解难度上差非常多:

认知复杂度简单规则

  • 代码中用到一些语法糖,把多句话缩为一句,但是代码不会变得更复杂
  • 出现"break"中止了线性的代码阅读理解,如出现循环、条件、try-catch、switch-case、一串的and or操作符、递归,以及goto类跳转,因此代码因此更复杂
  • 多层嵌套结构使得代码因此更复杂

认知复杂度评分规则

忽略简写:把多句代码缩写为一句可读的代码,不改变理解难度;

在认知复杂度的制定想法中,一个指导性的原则是:激励使用者写出好的编码规范。也就是说,需要无视或低估让代码更可读的feature(不计算进复杂度)。

“方法”本身就是一个朴素的例子,把一段代码拆的把几句抽离成一个方法,用一句方法调用代替掉,“简写”它,认知复杂度不会因为这这一次方法调用增加。
同样的,认知复杂度也会忽略掉null-coalescing操作符,x?.myObject这样的操作符不增加复杂度,因为这些操作同样是把多段代码缩写为一项了

对线性的代码逻辑中,出现一个打断逻辑的东西,难度+1;

在认知复杂度的制定想法中,另一项指导原则是:结构控制会打断一条线性的流从头到尾走完,使代码的维护者需要花更大功夫来理解代码。在认定了这会导致额外负担的前提下,认知复杂度评估了以下几种会增加Structural类复杂度:

循环: for, while, do while, ...

条件: 三元运算符, if, #if, #ifdef...
另外,以下这种会计处Hybrid类复杂度:

else if, elif, else, ...
但不计入Nesting类复杂度,因为这个量在计算之前的if语句时已经计过了。
这些增加复杂度,其实和圈复杂度的计算方式非常像,但是额外的,认知复杂度还会计算

当打断逻辑的是一个嵌套时,难度+1;

与连续嵌套的五个结构比,线性连续的五个if\\for结构要好理解得多。因为这样的嵌套会增加理解代码的成本,所以认知复杂度在计算时会将其视为一个Nesting类复杂度增加。
特别地,每一次有一个导致了Structural类或Hybrid类复杂的结构体,嵌套了另一个结构时,每一层嵌套都要再加一次Nesting类复杂度。

进一步说,复杂度得分是来源于以下几种不同的类型:
A. Nesting:把一段代码逻辑嵌套在另一段逻辑中;
B. Structural:被嵌套的控制流结构;
C. Fundamental:不受嵌套影响的语句;
D. Hybrid:一些控制流结构,但不包含在嵌套中;
然而不同类型在数学上没有区别,都只是对复杂度加一。在要计算的不同类别之间进行区分,可以更轻松地了解某一处是否适用嵌套的逻辑。以下各节将进一步详细说明这些规则及其背后的原理。

如果你对它有更好的兴趣,你可以看下官方的介绍文档:https://www.sonarsource.com/docs/CognitiveComplexity.pdf

 

以上是关于Sonar:Cognitive Complexity认知复杂度的主要内容,如果未能解决你的问题,请参考以下文章