早期报表和圈复杂度

时间:2014-09-15 06:37:07

标签: cyclomatic-complexity sonarqube

我更喜欢早期回报的写作风格:

public static Type classify(int a, int b, int c) {
    if (!isTriangle(a, b, c)) {
        return Type.INVALID;
    }
    if (a == b && b == c) {
        return Type.EQUILATERAL;
    }
    if (b == c || a == b || c == a) {
        return Type.ISOSCELES;
    }
    return Type.SCALENE;
}

不幸的是,每个return语句都会增加Sonar计算的圈复杂度指标。考虑这个替代方案:

public static Type classify(int a, int b, int c) {
    final Type result;
    if (!isTriangle(a, b, c)) {
        result = Type.INVALID;
    } else if (a == b && b == c) {
        result = Type.EQUILATERAL;
    } else if (b == c || a == b || c == a) {
        result = Type.ISOSCELES;
    } else {
        result = Type.SCALENE;
    }
    return result;
}

Sonar报告的后一种方法的圈复杂度低于第一种,为3.我被告知这可能是CC指标错误实施的结果。或者声纳是否正确,这真的更好吗?这些相关问题似乎不同意:

https://softwareengineering.stackexchange.com/questions/118703/where-did-the-notion-of-one-return-only-come-from

https://softwareengineering.stackexchange.com/questions/18454/should-i-return-from-a-function-early-or-use-an-if-statement

如果我添加对更多三角形类型的支持,return语句将相加以使指标发生显着差异并导致Sonar违规。我不想在方法上粘贴// NOSONAR,因为这可能会掩盖将来添加到方法中的新功能/错误导致的其他问题。所以我使用第二个版本,即使我不喜欢它。有没有更好的方法来处理这种情况?

3 个答案:

答案 0 :(得分:2)

不是一个真正的答案,但是评论的时间太长了。

这条SONAR规则似乎彻底打破了。你可以重写

b == c || a == b || c == a

作为

b == c | a == b | c == a

并且在这个奇怪的游戏中获得两分(甚至可能有一些速度,因为分支是昂贵的;但这仍然取决于JITc,无论如何)。

old rule声称,圈复杂度与测试次数有关。 new one没有,这是一件好事,因为很明显,两个片段的有意义测试数量完全相同。

  

有没有更好的方法来处理这种情况?

实际上,我确实得到了答案:对于每次提前退货,请使用|代替||一次。 :d

现在认真对待:有一个错误要求annotations允许禁用单个规则,该规则被标记为已修复。我再也不看了。

答案 1 :(得分:2)

您的问题与https://jira.codehaus.org/browse/SONAR-4857有关。目前,所有SonarQube分析仪都在混合环成复杂性和基本复杂性。从理论的角度来看,return语句不应该增加cc,这种变化将在SQ生态系统中发生。

答案 2 :(得分:0)

由于问题也是关于早期返回语句作为编码风格,因此考虑大小对返回方式的影响会很有帮助。如果方法或函数很小,少于30行,则早期返回没有问题,因为读取代码的任何人都可以一目了然地看到整个方法,包括所有返回。在较大的方法或功能中,早期返回可能是无意中为读者设置的陷阱。如果早期返回发生在读者正在查看的代码之上,并且读者不知道返回高于或忘记它在上面,则读者将误解代码。生产代码可能太大而无法放在一个屏幕上。

因此,无论谁管理复杂性的代码库,都应该在复杂性出现问题的情况下考虑方法大小。如果代码占用多个屏幕,则可以证明更为迂腐的返回方式。如果方法或功能很小,请不要担心。

(我使用Sonar并遇到过同样的问题。)