代码扫描的目的
代码扫描是保障代码质量的有效手段,通过代码扫描能够避免低级bug发布到线上导致严重故障的发生。代码扫描和人工review作为互补,弥补人工run代码的不可靠,review则弥补代码扫描这种机械硬编码条件所不能发现的错误。
代码的健壮性也是保证代码质量的前提,统一的编码规范甚至格式化规范能够为人工review降低代码阅读的难度,从而提升发现问题的概率,也降低分支合并冲突让人抓狂的冲突处理出现。痛苦的code review 往往会把人劝退。
语言覆盖需求
可基于公司后端技术栈考虑。
代码扫描时机
将未经过代码扫描和code review的分支直接合并到master分支是危险的。
除了合并PR时的代码扫描,开发阶段的代码扫描也很有意义,能够及时纠正编写错误的代码,也应该力推开发同事去使用。
扫描工具调研
Alibaba Java Coding Guidelines
- 支持的语言: Java
- 支持的特性: 阿里巴巴 Java 开发手册主要包含命名规范、代码格式规范、注释规范、代码逻辑规范、安全规范、并发规范和代码质量规范等方面的检测内容
- IDEA插件: Alibaba Java Coding Guidelines
- maven插件: p3c-pmd-maven-plugin(基于pmd的maven插件做的二次开发,扩展了pmd支持阿里巴巴代码规则)
- 自定义/扩展: 不支持(除非基于源码二次开发)
- 备注: 要求遵守阿里巴巴的开发规约
CheckStyle
- 支持的语言: Java
- 支持的特性: 可以检查代码的风格、格式、Javadoc、命名约定以及代码结构等方面的问题
- IDEA插件: QAPlug-Checkstyle
- maven插件: maven-checkstyle-plugin
- 自定义/扩展: 可定制和扩展(提供插件机制)
- 备注: 主流的开源项目如spring cloud、dubbo、sofastack都使用了CheckStyle
PMD
- 支持的语言: Java
- 支持的特性: 可以检查代码的规范问题、代码质量和复杂度问题、不良实践和潜在 Bugs、安全漏洞问题以及代码设计问题等
- IDEA插件: QAPlug-PMD
- maven插件: maven-pmd-plugin
- 自定义/扩展: 可自定义规则(提供插件机制)
FindBugs
- 支持的语言: Java
- 支持的特性: 可以检测空指针引用、类型安全问题、并发问题、资源释放问题、潜在错误和不良实践以及性能问题等
- IDEA插件: QAPlug-FindBugs
- 提供maven插件: findbugs-maven-plugin
- 自定义/扩展: 可自定义规则(提供插件机制)
SonarLint(Sonar)
- 支持的语言: Java, JavaScript, C/C++等(但不支持go)
- 支持的特性: 可以检测代码的规范和风格问题、安全漏洞、潜在的 Bug、代码复杂度和设计问题以及单元测试覆盖率等
- IDEA插件: SonarLint
- maven插件: 无
- 自定义/扩展: 可自定义规则(提供插件机制),可以集成Checkstyle、PMD等
- 备注: SonarLint是一个IDE插件,提供实时的代码分析和修复建议,可将代码上传到SonarQube进行分析。
SonarQube(Sonar)
- 支持的语言: Java, JavaScript, C/C++等
- 支持的特性: 复杂度分布、重复代码、单元测试统计、代码规则检查、注释率、潜在的Bug、结构与设计等方面的检测和展示
- IDEA插件: SonarLint (将代码上传到SonarQube进行分析,并接收分析结果,将结果反馈到IDE显示)
- maven插件: sonar-maven-plugin(SonarScanner的maven插件,SonarLint是一个IDE插件,提供实时的代码分析和修复建议,而SonarScanner是一个命令行工具,用于在持续集成和构建流水线中执行离线代码分析。)
- 自定义/扩展: 在服务端统一配置规则、通过插件提供扩展(例如可使用sonar-pmd插件)。
sonar-scanner的maven插件是对sonar-scanner的封装。
sonar-scanner的工作原理:sonar-scanner从SonarQube下载扫描插件(对于Java语言,默认是sonar-java-plugin),在本地执行扫描,然后将结果压缩上报给SonarQube。
可整合其它工具,例如PMD,如果配置Java使用sonar-pmd-plugin插件,那么sonar-scanner从SonarQube下载的扫描插件就是sonar-pmd-plugin插件。
sonar-scanner源码分析:https://github.com/sonar-next/document/blob/master/sonar_scanner_1.mdsonar-scanner-engine
源码分析:https://github.com/sonar-next/document/blob/master/sonar_scanner_engine.md
工具选型说明
仅考虑开发阶段
Alibaba Java Coding Guidelines工具能力比较齐全,但要求我们团队的编码风格必须符合阿里巴巴开发规约,而阿里巴巴开发规约限制太多,也存在很多有争议的条约。
CheckStyle在开源项目用的比较多,但缺少代码质量、安全漏洞、潜在bug等能力,而FindBugs则缺少代码规范的支持,可以考虑CheckStyle+FindBugs的选型,刚好是互补。但FindBugs相比SonarLint、PMD还缺少安全漏洞的支持。
针对代码规范,哪个工具其实都无法百分百满足我们的需求。SonarLint和PMD支持定义选择哪些规则,以及支持自定义规则,默认的规则也很轻量,针对无争议的规则默认选择支持,针对有争议的规则可团队讨论决定是否使用。因此选型SonarLint或者PMD,都非常合适。
是否支持maven插件的好处:可以配置在check失败时终止打包,强制开发者必须按check结果修改直至check通过后才可以打包成功,相比idea插件启动强制性作用。但也支持idea插件才更好,maven插件check失败的结果无法做到idea插件扫描结果提供“导航到问题处”的能力。maven插件起到强制check的作用,idea插件辅助修改check结果。
以PMD为例,通过maven插件配置在编译阶段check,如果check失败则会终止maven package。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.14.0</version>
<executions>
<execution>
<id>pmd-check</id>
<phase>compile</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
全流程考虑
选择SonarQube+SonarLint+SonarScanner比较符合企业使用。SonarQube作为平台,可以统一配置代码规则、统一配置插件以及插件的版本更新,通过不同插件支持多语言。
开发阶段:使用SonarLint只作为SonarQube的客户端IDEA插件,与SonarQube集成,通过将代码上传到SonarQube扫描,并将扫描结果展示到IDEA。
PR阶段:通过gitlab-ci集成SonarScanner(例如SonarScanner for Maven),扫描结果在SonarQube平台展示,并给PR添加评论。
SonarLint、SonarScanner默认都是使用sonar-java-plugin插件实现Java代码规则检查、潜在的bug检查,支持定义规则。我们也可选型其它如PMD作为SonarQube的代码扫描插件。