提升代码质量:代码检查工具规模化使用实践
原创作者:雷晓宝
本文旨在分享使用源代码静态检查工具的实践经验(如规则制定、报告解读),以及如何在组织中开展这类工具的推广应用。你将会了解这类工具的概念模型、规则的制定策略以及如何有效地使用。
自编程诞生以来,开发团队就在和缺陷(BUG)做斗争。一个个工具发明出来以期提前发现缺陷。从编译器内置的告警到独立的工具,各具特色。这类工具统称为 “静态/动态分析服务”(software static/dynamic analysis service,ISO/IEC 15940:2013)。
本文中主要关注其中的静态分析服务、测度、规则、报告,简称为检查工具、规则。
从软件测试的角度来看,代码评审以及使用静态分析工具发现缺陷是静态测试活动。是保障软件质量而必须做的。
为能做好静态测试,必须要制定合适的规则、规范,开展合理的推广应用,才能让检查工具发挥最大的价值。下面就从「规则的制定」、「工具与规则的应用」两大方面展开,同读者朋友分享我们最新的可落地实践。
先澄清一些概念。如图1,检查工具装载规则集,接着扫描源代码或编译产物,最后分析并输出执行报告。

图1-检查工具的概念模型(体现各种概念间的关系)
规则集由多个规则组成。一个规则可以定义为源代码中的某种检查点。如果工具在分析源代码时发现与某规则匹配,则向执行报告中添加一个议题(issue,也有称之为问题的),用以说明源代码中什么地方违反该规则。规则和议题是1对多关系。规则可以带参数,例如每一行所允许的最多字符数是可调整的。
规则有两个主要特征:分类(type)和优先级(priority或severity)。分类是指问题类型,例如可能的缺陷、安全风险、代码格式等。优先级则是重要程度,常见、5级或3级,例如:重要、一般、次要。
执行报告包含多项议题。每个议题同样会有分类分级参数(继承自规则)和其他属性,如引入时间、作者、在源文件中的位置、状态、处理措施等。
同样是Java,在编写移动端、桌面、图形用户界面、前台、后台、数据处理等不同场合的软件时所遵守的规则是有差异的,甚至同一个软件不同需求遵守的规则也不同。误用规则就会出现水土不服。
只有与场合无关的规则才能纳入到基本规范。常见的误用(如Random、SimpleDateFormat、finaly+return)或常犯的错误(如逻辑矛盾、空指针),或特定版本的缺陷。
此外,大量规则是与应用场景有关系的,在采用前应当仔细理解设计立意,分析适用场景,结合自身技术特征来决定采用。对那些不符合使用场景或过时的规则应当弃用。
按照基本规范加场景组合的方式制定规则集,更容易让团队接受并使用。简单照搬类型或等级来组织规则最终得到的还是很多误报,让团队放弃。
对工具或规则的效果开展实地分析,用数据来指导工具或规则的配置。
请看这个实验数据(表1)。我们使用免费的持续集成与代码扫描服务开展一次实验,以知名开源项目spring-framework为基线代码,套用不同规则集来执行分析,收集结果。
表格1-一次工具执行时长实验
工具或规则 | 规则 数量 | 耗时 | 底层工具 | 备注 |
全语种敏感信息扫描 | 6 | ≈3分钟 | RegexScan | |
Java基础规则包 | 102 | ≈10分钟 | Cobra、PMD | |
Xcheck | 20 | <1分钟 | Xcheck | |
Java代码规范包 | 53 | ≈1:37:00 | CheckStyle、CustomFileScan | CheckStyle耗时最大 |
Java减包扫描 | 4 | ≈1分钟 | PMD | 要求编译 |
Java安全规则 | 95 | ≈32分钟 | Cobra、PMD、SpotBugs、SQJava、InferJavaCustomized | 要求编译 其中InferJavaCustomized耗时最多 |
Java功能规则 | 126 | ≈6分钟 | SQJava、SpotBugs、InferJavaCustomized | 要求编译 |
代码重复检查 | —— | ≈2分钟 | CPD | —— |
圈复杂度 | —— | ≈2分钟 | Lizard | —— |
代码行统计 | —— | ≈1分钟 | CodeCound | —— |
实验环境:Coding免费的构建资源池与环境(8核/16GB/100GB磁盘空间/ubuntu 2023.5.25),选择开启构建缓存。
基线代码:Spring Framework 6.0.x分支2023.5.25日副本。构建工具为gradle。百万规模(1438598行),约58%(80万)源代码;15%空白行;27%注释行。
实验方法:创建主动扫描,为每一种规则集配置一个扫描方案,执行三次,记录执行时长,取最小值。
提示:代码扫描的执行时长还收到并发抢占等因素的影响,一时的结果不作为永久判断依据。超长的执行时间还可能受到构建工具错配、网络下载或编译等的影响。此次结果仅用来说明工具与规则需要准确配置才能发挥作用,错误配置的干扰也会影响工具的使用体验。
数据可以佐证我们的观点,应当根据执行时长等数据来决定工具的采用策略。太耗时间的工具显然不能用到频繁集成的场景中。同样,可靠性低,误报多的规则也应当关闭。
大量实践表明,小于5分钟的执行时长普遍可以接受,5到10分钟有些勉强,而超过10分钟就难以忍受。
继续对扫描结果进行分析,导出报告做分类汇总,形成如表格2的统计:
表格2-对不同分级做统计分析
分级 | 议题总数 | 平均到月的数量 (2009年——2022年,156个月) |
1 致命 | 0 | 0 |
2错误 | 357 | ≈3 |
3警告 | 7474 | ≈44 |
4提示 | 38115 | ≈244(估算值,无法导出,未分析) |
反推工具效果,留存的议题可能有三种情况,评审后无需修改、误报或者项目并没有遵守这一规则。
致命、错误类留存少,说明这两级的规则对项目是有价值的。
警告与提示类的误报相当多,对真正问题的识别造成干扰,影响使用体验。在频繁的使用中应该谨慎关注。
当工具上升到组织级规模化、统一化应用时还有新的挑战需要注意,工具应当方便大家学习使用,方便管理员批量配置更新。
搭建网站对工具与规则进行详细说明。特别要说明问题的修复方法,避免大家不知所措。这是一个内容建设任务,不用专门开发工具,wordpress、wikipedia也能够承担此任。
得益于组织的知识共享机制,新建项目时可以沿用相似项目检验过的规则进行配置,减少重复建设成本。
四、设计规则集的下发机制
根据规则集的管理方法,设置组织级工具使用规范,便于组织规模化推广。
诸如SonarQube支持规则集继承,子集不能关闭父集的规则但能调整优先级,符合组织集中管理工具配置的诉求。但是实践中会遇到一个难题,配置管理员会成为工作瓶颈,一旦规则配置不佳,团队很容易抱怨效果差而弃用。
还有工具采取的是「克隆+屏蔽」的方式。从组织级规则集克隆出团队的规则集,并允许宽松的调整规则。这样的好处是组织层面的配置管理压力小,即便有一些错误,团队也可以自行调整克服。当然也有不足,规则更新后的下发会成为难题,批量的下发会重置团队的规则配置。
两种方式各有优势,适合应用于组织不同的发展阶段。个人经验,「克隆+屏蔽」方式适合组织逐步地建立代码检查体系。在组织掌握规则的管理经验和机制后,可以再采取办法来统一下发规则。
受能力与精力所限,管理员很难熟悉每个规则在一线的实际应用效果。所以,规则应当交由专精的人员来维护。组织可以成立开发委员会,由各技术栈的专家来维护规则集。
可选择典型的项目应用全量规则,按本文介绍的思路调整配置,输出第一稿规则集。后续再按半年或一年的频率来调整。
同时允许团队向组织贡献规则的配置经验,共同维护规则集。
团队还要掌握工具的运行时机以及正确解读报告的技能。
在流水线中集成代码检查工具可以实现强门禁的机制保证,限制问题数量。
单纯使用检查工具有短板,与版本控制系统、持续集成结合才能获得为更丰富问题上下文,有利于快速排查与解决问题。
版本控制系统可以提供代码变更的时间、作者。这样执行报告中就能准确地体现议题的出现时间和责任人。
对照工具的执行记录以及版本控制系统提供的变更记录,持续集成服务就能推算出增量代码,在变化的代码上运行工具,并推算增加的议题,节约一定的运行时间。
再进一步,可以用基线分支作对照,计算新代码分支中新增加的问题,实现增量门禁。增量门禁卡点是大规模落地检查工具的关键成功因素。如果没有这项能力,就只能先将存量问题清理完毕,再开启代码检查门禁。
此外,检查报告可以和代码合并评审集成,在代码评审界面中既能看到代码的变化,又能看到代码检查报告,方便代码评审。
检查工具不局限于在持续集成中运行。实际工作中可以将某些规则前置到开发工具里。比如代码的格式化,适合在编写代码的同时使用格式化功能一次性处理好,如果放在后面阶段检查反而因议题太多而淹没真正的问题。
有些则适合在代码提交前进行检查,过早的关注反而会分散精力,例如多余局部变量、方法。
首先议题是不是团队认可的问题,其次问题是否就一定要修正,这两个过程都是需要团队进行复核的。这和“缺陷”要复现才能算作缺陷,是一样的道理。
复核检查报告,确认不改、排除误报也是代码评审要做的工作。确认为待修复的问题后就需要安排时间修复,重新提交代码并触发扫描后,问题会自动关闭。整体的工作流程如图2:

图2-议题处理流程
检查规则应当经过调整以后再规模化应用。可以试着以不同技术栈、运行时长、误报率的角度分析整理规则集。还要保持一定的修订频率,跟着技术升级而升级。
将审阅检查报告与修复证实的问题作为人工评审的前置条件。工具先帮助排除一些问题,人工评审做更重要的事情。
要正确解读报告。排除误报、关闭事项也是代码评审活动的一部分,确认的问题要及时修复。
本文主要介绍代码检查工具使用策略。工具能辅助代码评审发现固定范式问题但存在误报,期待AI加持的新一代检查工具能够提高问题发现能力,降低误报。
参考资料
[1] SONARQUBE中ISSUE的的概念和属性,https://docs.sonarsource.com
[2] GB/T 30972——2014 系统与软件工程 软件工程环境服务