完善代码质量是大多数软件开发者的共同目标,但是虽然意图非常明确,实现它的策略却可能非常复杂。衡量方式和衡量对象是改善审查过程效果的关键因素。
对于尊崇持续改进、持续关注技术卓越和定期反思原则的团队来说,尤其如此。凭借 20 多年的软件开发经验,JetBrains 收集了一些见解,可以分享哪些指标对于团队而言最有效。
实用代码质量指标及其衡量方式
1. 循环复杂度 (CYC)
CYC 是基于源代码中独立路径数量来衡量程序代码流复杂度的指标。这是一项重要指标,因为随着复杂度的提高,代码会变得更加难以理解、测试和维护。 如果您遵循敏捷方式,可持续性和可维护性就至关重要。这正是 CYC 的用武之地,可供您洞察哪里可能需要简化。
让我们用一个简单示例来演示这项指标如何运作。考虑一段仅顺序执行语句的代码段,无任何条件或分支:
public int sum(int a, int b) {
System.out.println("Adding two numbers: " + a + " + " + b);
return a + b;
}
由于代码没有分支,无论形参值如何组合,函数中的所有语句都会执行。因此,此代码的 CYC 结果为 1。
如果我们引入一个条件语句来检查输入,CYC 将翻倍,因为我们的代码将包含两个可能的执行路径,而非单个分支:
public int sum(int a, int b) {
if(a < 0) throw new IllegalArgumentException("Parameter a should be positive");
System.out.println("Adding two numbers: " + a + " + " + b);
return a + b;
}
添加另一项条件来测试第二个形参会将 CYC 结果提高到 3:
public int sum(int a, int b) {
if (a < 0) throw new IllegalArgumentException("Parameter a should be positive");
if (b < 0) throw new IllegalArgumentException("Parameter b should be positive");
System.out.println("Adding two numbers: " + a + " + " + b);
return a + b;
}
任何条件语句或循环块都会体现在方法的 CYC 指标中,从而增加执行所有代码分支所需的测试次数。
虽然高 CYC 值并不能直接表明代码存在 bug 或受损,但确实可以表明代码可能难以维护,因此新增更改时会更容易受损。IntelliJ IDEA 可以直接在编辑器中向您告知过于复杂的方法。Overly complex method(过于复杂的方法)检查的阈值可以在 Settings | Editor | Inspections(设置 | 编辑器 | 检查)中进行配置:

默认情况下,阈值设置为 10。不过,如果我们将此指标更改为 2,编辑器将高亮显示上例中的代码:

如何对整个项目启用此检查
如果您使用 Qodana 进行服务器端代码分析(跟踪整个团队的代码质量,而不仅仅是本地),可以自动检查 CYC。选择推荐的配置文件,并检查它是否已针对您的编码语言启用。

解释结果
Tom McCabe Jr. 在面向国土安全部的演讲《用于识别风险的软件质量指标》[下载] 中表示,如果方法的 CYC 指标值小于 10,则代码会被认为足够简单。
如果指标超过 50,则代码会被认为过于复杂且无法测试。但在实际情况中,您应以低于 6 的值为目标,并设置在结果超过 10 时发出警告。这表明是时候简化函数以防止复杂度进一步提高了。
我们建议的 CYC 分数范围如下:
1–5:代码简单,易于测试和调试
6–10:更复杂,风险适中
10-20:高风险,须谨慎
20+:代码非常复杂,难以理解和维护
2. 代码重复百分比
代码重复百分比可以帮助您确定代码库中的多个位置出现了多少相同或相似的代码。这是一项重要的指标,因为大量的重复代码会导致维护量增加、引入错误的几率更大,以及代码可读性下降。
使用 Qodana,重复检查会默认启用,但您也可以在 IntelliJ IDEA 和其他 IDE(例如 WebStorm 和 Rider)中配置重复检测。


解释结果
理想情况下,您应将代码重复百分比控制在 5% 以下。这有助于避免不必要的重构 – 为了一处改进或问题而更改多处代码。请确保使用诸如 Qodana 等工具在本地或服务器端持续监控代码重复情况。
3. 代码(测试)覆盖率
编写具有最大覆盖率的测试用例可以帮助您在手动测试之前验证软件是否按预期执行。通过更有效的测试,您有机会更快地将高质量产品推向市场。
另外,高测试覆盖率可以增强可维护性,并且可以提醒您注意冗余代码,因为它在衡量时假定较高的覆盖率会减少代码缺陷。
衡量代码测试覆盖率的最常用方法是通过代码行数进行计算:
代码覆盖率 =(算法测试的代码行数/系统组件的代码总行数)* 100
不过,还有另外两种策略:
1) 按语句衡量
2) 按分支衡量,这与循环复杂度指标更相关,因为复杂度可以表明覆盖代码需要实现多少次测试。
评估代码覆盖率
如果您拥有 Qdana Ultimate 或 Ultimate Plus 许可证,并使用适用于 JVM、JS 或 PHP 的 Qodana,则可以在 qodana.recommished 或 qodana.starter 配置文件中运行代码覆盖率测试。在此处了解如何设置代码覆盖率衡量。

4. 可能的 bug 数量
显然,我们希望代码中的 bug 数量尽可能接近于零,并且代码分析能够标记所有类型的错误。一个示例是 NullPointerExceptions,当我们尝试执行需要对象的运算时会引发该异常。导致此异常的原因通常是在运行时为 null 的对象实例上使用方法或尝试访问该实例的变量。
这些问题必须尽早发现以避免发布存在 bug 的产品版本,特别是您可能不会立即注意到代码中存在这些问题,甚至在同行评审流程中也会将其遗漏。Qodana 可以轻松控制与不正确的资源处理相关的问题,例如数据库连接在使用后未安全关闭。
5. 代码异味
衡量代码异味(例如已弃用的 API 用法)对于维护软件代码库的健康非常重要。尽管可以手动评估已弃用的 API 用法,即让审查者识别已弃用的 API 并提供替代建议,但最常见的方式是使用 Qodana 等静态代码分析工具。
6. 漏洞数量
代码中的漏洞是指可能导致安全漏洞、数据泄露或其他安全相关问题的安全弱点或问题。
即使只是一个漏洞也可能会导致重大的安全漏洞。我们只需要以 X(前 Twitter)、CloudFlare 和 AWS 为例,他们都曾遭受过 Log4J 漏洞的严重影响。这些漏洞会以多种形式表现出来,例如安全漏洞、配置错误、访问控制问题、依赖项漏洞等。


在上方您可以看到,Qodana Cloud 的一项检查将标记存在漏洞的依赖项。您还可以使用 Qodana 数据检查依赖项许可证。
一旦确定了代码中的漏洞数量,您就可以评估哪些漏洞最为严重且最具风险。随后,您即可立即着手处理优先级最高的问题,并将不太严重的问题保存到基线以便稍后解决。
通过静态代码分析
简化代码质量衡量
代码质量指标有助于指导您获得更加简洁、高效、易维护的代码。这些指标可以帮助您全程全面了解项目健康状况,赋予您改进产品和开展团队协作的战略优势。
如果您希望将这些指标实现到交付流程中,Qodana 可以提供帮助。它完美契合任何 CI/CD 工作流,可为您的整个团队提供衡量代码质量的单一可信来源。最重要的是,它的扫描结果在 JetBrains IDE 中开箱即用,这使您能够快速修正问题。
立即开始试用,并告诉我们您最依赖哪项指标。如果您想更深入地了解如何衡量代码质量,请与我们联系:
中文技术支持:support.cn@jetbrains.com
中文销售支持:sales.cn@jetbrains.com
本博文英文原作者:Anton Arhipov, Kerry Beetge
Qodana 相关阅读

⏬ 戳「阅读原文」了解更多信息
本文分享自微信公众号 - JetBrains(JetBrainsChina)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。