代码质量保障,从零到强制检查
代码质量保障,从零到强制检查
dong4j推行代码检查,最难的不是技术
代码质量保障是个经典话题。Checkstyle 做格式检查,PMD 做逻辑缺陷检查,SonarQube 做全方位的代码质量度量——这三件套怎么用,网上文档很全。
但真正的挑战从来不是”怎么配置这些工具”,而是**怎么让一个已经运行了两年的、代码量不小的、团队成员流动频繁的项目接受”强制代码检查”**。
想象一下这个场景:你在 CI 管道里加上了 Checkstyle,规则用的是 Google Java Style。第二天,所有 MR 都挂了——不是代码逻辑有问题,而是缩进不对、命名不规范、缺少 Javadoc。开发 leader 来找你:”能不能先关掉,这个需求很急。”你说不能。他说那就先降级为 warn。
然后这个 warn 就永远是 warn 了。没人看 warn。
这不是假设,这就是大部分项目型组织中推行代码质量工具的真实路径。所以我花了大量时间思考的不是”选哪个工具”,而是”怎么让别人愿意用”。
工具分工:各干各的,互相补充
先简单过一下三件套的定位。
Checkstyle 管格式。缩进是 4 个空格还是 tab?大括号是同行还是换行?类名是大驼峰还是什么?这些东西和逻辑无关,和审美有关。但审美不统一,代码仓库看起来就永远像多个人写的——虽然确实是多个人写的,但读代码的人不应该感知到这一点。
规则直接基于 Google Java Style,再做项目级调整。比如行长度限制设 140 字符而不是默认的 100——别问为什么,问就是团队共识。
PMD 管逻辑。它基于 AST(抽象语法树)分析代码,找的是真正的 bug 模式——循环里用 += 拼接字符串、用 == 比较字符串、SimpleDateFormat 当静态变量用、ThreadLocal 不调 remove。这些不是格式问题,是线上事故的种子。
PMD 的规则比 Checkstyle 更容易引起争议。因为格式问题可以靠”格式化一下就行”解决,但 PMD 报的问题有时需要改逻辑——比如把 String result = ""; for (...) result += item; 改成 StringBuilder。开发者会说”这里循环体量很小,不会有性能问题”。你说得对,但规则不讲感情,规则讲一致性。
SonarQube 管全局。它不是检查单行代码,而是从项目维度看代码质量——可靠性(Bugs)、安全性(Vulnerabilities)、可维护性(Code Smells)、测试覆盖率、重复率、复杂度。它有一个核心概念叫 **”Clean as You Code”**——不强求一次性修复所有历史债务,但要求新增代码达到质量标准。
这个理念在老旧项目中特别实用。你面对一个几十万行代码的项目,让团队花三个月把 Checkstyle 的几千个 warning 全修完?不现实,也没人愿意干。但”从今天开始,新增代码和修改代码必须通过检查”——这个要求是合理的,也是可以执行的。
怎么让规则不惹人烦
规则配置是推行成败的关键。配得太严,团队反弹;配得太松,等于没配。
我定的规则集中放在一个独立的 checkstyle-rules 模块中,通过 Maven 依赖的方式提供给所有业务项目。这样改一次规则,所有项目自动生效:
1 | common-parent/ |
PMD 的规则我按类型拆了十几个文件,但真正启用的是这六类:
concurrent.xml:手动创建线程、Executors 工具类创建线程池、静态 SimpleDateFormat、ThreadLocal 未 remove。这些是”写对了是运气,写错了是事故”的问题。
exception.xml:finally 块中使用 return、事务没有 rollbackFor。都是静默破坏流程的写法。
naming.xml:类名、方法名、变量名、包名、抽象类以 Abstract 开头、异常类以 Exception 结尾、测试类以 Test 结尾。如果连名字都统一不了,就别谈规范了。
oop.xml:== 比较字符串、== 比较包装类型、循环中 String 拼接、BigDecimal 用 double 构造。
set.xml:foreach 中修改集合、Arrays.asList 后修改、集合初始化不指定容量。
other.xml:方法中编译正则表达式、使用 Apache BeanUtils、浮点数直接比较。
Checkstyle 的检查先于 PMD 执行。为什么?因为格式问题占了 80% 的违规,如果格式都没过,就别浪费 PMD 的时间了。
1 | <!-- 父 POM 中的配置 --> |
编译时不通过就 fail fast。不搞 warn,只搞 error。warn 没人看,error 才有人修。
IDE 集成
CI 检查是最后的防线,但最好的检查是在代码还没提交的时候就发现问题。
Checkstyle 在 IntelliJ IDEA 中有官方插件,安装后指向项目中的 checkstyle.xml,写代码的时候就能看到波浪线提示。PMD 也有插件,但我没强制推广——PMD 的问题量少,编译前统一处理即可。插件太多也会拖慢 IDE。
另一个关键配置是 IDEA 的代码风格文件。把团队统一的风格配置导出为 codestyle.xml,放在仓库里,新成员加入时导入一下就行。缩进、空格、换行这些格式问题,80% 可以通过 IDE 自动格式化解决。
但这有个问题:IDE 的配置文件会过时。你在仓库里放了一份 codestyle.xml,三个月后 IDE 升级了,或者团队调整了规则,文件没更新。更理想的方式是通过 IDEA 插件来管理代码风格——类似 checkstyle-rules 模块的思路,插件按需从远程拉取最新的规则。不过这是长期规划的事了。
给特殊情况留后路
规则不可能覆盖所有场景。有些代码生成器生成的代码,风格和手动写的完全不同。有些测试方法名确实需要很长。这些情况需要通过抑制机制来处理。
被动的抑制:在 checkstyle-suppressions.xml 中配置全局排除规则:
1 | <suppressions> |
主动的抑制:代码中注解标记:
1 |
|
关键是抑制必须有明确原因。code review 时看到 @SuppressWarnings 就要问:为什么要抑制?有没有更好的写法?抑制不是偷懒许可证。
紧急情况下的逃生舱
生产环境出问题,需要紧急修复,代码检查可能成为阻碍。这是合理的担忧。解决方式是在 Maven 命令中允许跳过:
1 | # 紧急部署时跳过所有代码检查 |
但跳过是例外,不是常态。每次跳过都应该有记录。你可以在 CI 管道里加一个简单的审计——检测到跳过参数时,自动发一条消息到团队群:”注意:XX 服务本次部署跳过了代码检查。”
推行的节奏:先小后大
回到开头的话题——怎么让别人接受。
我大概花了三个月做渐进式推行。第一个月,只在框架本身的模块中启用 Checkstyle,不做 PMD。让团队先习惯”构建可能因为格式问题失败”这件事。
第二个月,在修复了框架自身的问题后,向一个业务模块试点。同时提供 IDEA 配置文件和一键格式化指南——“如果你想在提交之前就解决大部分问题,导入这个文件然后 Ctrl+Alt+L”。
第三个月,全面推广到所有模块,同时启用 PMD。PMD 的初始规则只保留了并发、异常处理、集合操作这三类——选最能防 bug 的,不选最全的。规则集在后续版本中逐步增加。
这个节奏的核心原则是:让团队先感受到工具带来的好处,再增加工具的约束力。如果一上来就扔三百条规则,团队只会觉得你在给他们添麻烦。但如果他们先发现”咦,PMD 帮我发了一个潜在的 NPE”,接受度就完全不同了。
写到这里,整个系列已经覆盖了架构全景、工程规范、Response 设计、缓存重构、配置管理、代码质量——这些都是研发底座的”软”层面。下一篇也是最后一篇,聊点”硬”的:微服务网关的性能调优,从 context-path 设计到 Nginx 内核参数,都是线上真实踩过的坑。

















