【51CTO.com快译】众所周知,业界常把低质量的程序代码称为“技术债”。它们不但会影响软件构建的效率,而且会在软件交付和运行中,出现严重的服务质量问题。可见,软件质量的重要性是不言而喻的。本文将和您讨论在自动化的代码质量控制流程中,有关代码样式、正确性、复杂度、设计、安全性、覆盖率、以及审查等关键要素。
1.代码的样式
常言道:您的代码观感,直接反映了您对代码的关心程度。此言不虚,即使是那些代码段上的缩进不一致,也可能为代码的后期分析带来一场噩梦。更不用说由此产生的,不同开发团队在联调程序过程中的各种冲突了。
幸运的是,我们可以使用诸如Idea和Eclipse之类IDE工具,来自动化检查代码样式的方式,进而修复并提高代码的准确性。具体而言,开发团队中的每个成员首先应当使用相同的代码样式定义,将其设置为共享的.editorconfig文件、或特定于某个IDE的配置之中。其次,我们需要通过将样式检查集成到构建的过程中,以确保每个成员都能遵循代码样式规则。我们可以在每次将代码的更改推送到存储库时,通过Checkstyle的方式,采用Jenkins插件、Maven、以及Gradle的脚本来实现。
2.代码的正确性
代码扫描向来是一项耗时且繁琐的工作,有时甚至难免有所疏漏。对此,我们可以使用一些免费的工具,其中包括:SpotBugs(它是已废弃的FindBugs项目的继承者)、PMD、Error Prone、以及SonarQube。其中的一些还可以识别出重复性的代码,并发现潜在的性能问题。与Checkstyle相似,我们可以将这些工具集成到自己的IDE中,轻松地检查出目标代码中的缺陷。
此外,您也可以使用Checker Framework来增强Java系统的代码检查,以及防范潜在问题的能力。当然,您可能需要对其进行一些额外的手工配置。
值得注意的是,我们需要让这些工具在项目构建的过程中就事先运行起来,以免在将代码推送到存储库之前,忘记让它们“把关”了。
3.代码的复杂度
在前面的讨论中,我们主要关注的是发现代码中的常见编程缺陷。下面,让我们聚焦代码的复杂度。显然,没有人愿意阅读和使用那些难以推理、维护和扩展的代码。通常,我们可以使用如下指标,来衡量代码的复杂度:
- Cyclomatic和NPath复杂度 — 是基于控制流的复杂度计算方法。换句话说,它显示了在测试中,应当涵盖的不同路径的数量(可测试性)。我们可以使用的工具包括:Checkstyle、SpotBugs和PMD。
- 认知复杂度- 衡量的是代码对于人类理解能力的难度(可读性)。我们可以使用的工具包括:SonarQube和SonarLint的IDE插件。
4.代码的设计
下面,让我们来看看如何使用静态代码分析工具,来发现目标代码在设计上的缺陷。目前,许多面向对象的设计实践,都可以通过自动化的源检查(source checks),以发现继承层次(inheritance hierarchy)过高、以及上帝类(God class)等设计问题。对此,Checkstyle和PMD都提供了一整套检查工具。其中包括:Source code file、Class、Method、以及Parameter list。它们都能够根据基本设计规则,对代码进行全面检查。
除了上述基本的设计检查,我们还可以通过如下静态分析工具实现更深层次的检查:
- PMD的LawOfDemeter可用于减少各个类之间的紧密耦合。
- Checkstyle的DesignForExtension,实现了由Joshua Bloch撰写的《Java高效编程(Effective Java)》第三版的第17章:针对继承或禁止继承的设计和文档(Design and document for inheritance or else prohibit it)。
- PMD的CouplingBetweenObjects,通过唯一属性、局部变量、以及返回类型的数量等信息,来检测难以测试、分析和扩展的紧密耦合类。
- jPeek,可衡量类的内聚性,进而保持各种类、模块、以及包的高内聚性。
- embold,包含了大量针对耦合和内聚的有关高级设计缺陷的检查功能。
- CodeScene是从开源项目Code Maat处演变而来的。通过分析版本控制系统中有关历史代码的更改,它不仅可以发现潜在的设计问题,还能够发现开发中的瓶颈问题。
值得注意的是,最后两款工具仅对于开源项目是免费的。
5.代码的安全性
在开发过程中,为了确保代码的安全性、可扩展性、以及可维护性,我们需要持续检索CVE数据库,以避免第三方的依赖项出现安全漏洞。此外,您也可以从如下资源处获取有关代码安全的各种实践:
- 通用安全编码规则--OWASP TOP 10
- 特定技术安全编码规则--Oracle Java的安全编码准则
- 最常见的安全漏洞--Mitre CWE Top 25,SANS TOP 25
作为补充,下面是几种具有自动化执行功能的,代码安全性检查工具:
- FindSecBugs,是SpotBugs的插件,可用于审核Web应用中Java程序的安全性。您不但可以将其集成到Maven或Gradle之类的构建过程中,还可以在使用IDE插件进行编码时用到它。
- SonarQube是一个多合一的安全性检查工具。其母公司SonarSource在2020年收购了RIPS Technologies后,进一步提升了Sonar的安全检测能力。
此外,各种第三方的依赖项和Docker镜像,也能够在代码质量控制的过程中,实现各项安全性的扫描。
6.代码的覆盖率
常言道:如果没有大量的自动化测试,就无法验证代码是否能够按期运行;如果没有自动化的回归测试,就无法安全地重构代码。那么,我们又该如何在保证具有高质量的代码置信度的基础上,尽可能涵括更多的流程,检查并提高代码的覆盖率呢?显然,我们需要事先充分地准备好如下不同的测试覆盖率相关指标:
- 语句与指令的覆盖率,即:程序中有多少条语句已被执行。
- 代码行覆盖率,即:已测试了多少行源代码。
- 分支覆盖率,即:已经执行了目标控制结构中的多少个分支。
- 方法与功能覆盖率,即:定义了多少种方法。
在工具方面,我们可以使用IntelliJ IDEA的Coverage、Eclipse的JaCoCo等具有IDE的流行工具。
- 通过将Coverage工具集成到构建过程中,我们能够通过上述指标,来了解具体涵盖了代码的哪些部分,进而发现测试中的不足。
- JaCoCo可谓Java领域最流行的代码覆盖率工具。您可以通过Maven、Gradle、甚至是Ant,将其集成到构建的过程中。JaCoCo既提供了开箱即用式的支持,又可以从远程流程中收集到覆盖率的相关信息。同时,它也能协助我们将端到端的测试,包括在代码覆盖率的最终报告中。值得一提的是,Sonar也使用JaCoCo来监控那些随时间变化的代码覆盖率。您还可以针对新的代码覆盖率级别过低的情况,自定义质量门(Quality Gates)的通知与警报。
- OpenClover除了提供一组基本的覆盖率度量标准与集成之外,还包含了一组旨在提高代码覆盖率的度量标准。
- Cobertura曾经是Java最受欢迎的代码覆盖工具,不过目前已不再被维护与更新。
7.半自动化的代码审查
在整个代码管控的过程中,最复杂、且最难实现自动化的环节,当属代码审查。由于部分需要依赖手动来实现,因此该过程往往取决于审查者的技能、资历、甚至是态度,而且其结果也不尽相同。
例如,SonarQube仅在其付费版本中,提供了针对合并与拉取式请求的静态自动化分析。据此,您可以在打开某个合并式请求(Merge Request)时,登录到SCM,并在代码中直接查看到静态代码分析的结果。
而开发人员则主要会从如下方面开展代码审查:
- 功能性需求审查
- 特定项目的需求审查
- 高级设计或架构审查
- 代码复杂度和性能审查
因此,为了使代码审查的过程更能保持一致性,我们应准备好一份代码审查清单,以事先约定好手动代码验证的详细内容。对此,您可以参考Google的《代码审查之开发者指南,Code Review Developers Guide》。它在“代码审查”部分给出了一个简短的审查清单,以便实现整个团队在审查过程中的统一性。
原文标题:How To Keep Code Quality Under Control In 7 Steps,作者:Artur Kluz
【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】