14、代码质量工具:Spotless、Detekt、Checkstyle、PMD配置
代码质量这件事,说实话,很多团队一开始都不太重视。我记得刚入行那会儿,总觉得“能跑就行”。直到有一次,我接手了一个遗留项目,打开一个文件,好家伙,三千多行,缩进混乱,命名随心所欲,还有一堆死代码。那个下午,我对着屏幕发呆,心里只有一个念头:这代码要是能自动检查格式化就好了。
嗯,后来我成了那个在项目里“强行”推行代码质量工具的人。今天我们就聊聊 Gradle 里怎么配这些工具。说白了,就是让机器替你盯着代码规范,别等人来 review 的时候再吵架。
14.1 为什么需要代码质量工具?
你想想看,一个团队五六个人,每个人写代码的习惯都不一样。有人喜欢 tab,有人喜欢空格;有人变量命名用下划线,有人用驼峰。光靠口头约定,根本管不住。
代码质量工具能帮你做三件事:
- 格式化:让代码风格统一,看着舒服
- 静态分析:发现潜在 bug、性能问题、坏味道
- 强制执行:不合格的代码,构建直接失败
我个人习惯在项目一开始就把这些工具配好。别等到代码写了几万行再回头改,那成本就高了。
核心原则:代码质量工具不是用来“找茬”的,而是用来“兜底”的。它帮你守住底线,让 code review 可以聚焦在架构和逻辑上。
14.2 Spotless:代码格式化利器
Spotless 是我最常用的格式化工具。它支持 Java、Kotlin、Groovy、甚至 Markdown 和 YAML。配置起来也很简单。
先加插件:
// build.gradle.kts
plugins {
id("com.diffplug.spotless") version "6.25.0"
}
然后配置规则:
spotless {
kotlin {
ktlint() // 使用 ktlint 规则
target("**/*.kt")
targetExclude("**/build/**")
}
java {
googleJavaFormat() // Google Java 风格
target("**/*.java")
}
format("misc") {
target("**/*.md", "**/*.yml", "**/*.yaml")
trimTrailingWhitespace()
indentWithSpaces(2)
endWithNewline()
}
}
运行命令:
./gradlew spotlessApply // 自动格式化
./gradlew spotlessCheck // 只检查,不改
我的经验:建议把 spotlessCheck 挂到 CI 里。本地开发用 spotlessApply,提交前跑一遍,省得 review 时因为缩进问题来回扯皮。
14.3 Detekt:Kotlin 静态分析
Detekt 是 Kotlin 专用的静态分析工具。它比 ktlint 更“重”一些,能检查复杂度、代码异味、甚至性能问题。
配置方式:
// build.gradle.kts
plugins {
id("io.gitlab.arturbosch.detekt") version "1.23.6"
}
detekt {
buildUponDefaultConfig = true // 在默认规则基础上扩展
config.setFrom("$projectDir/detekt.yml") // 自定义规则文件
baseline = file("$projectDir/detekt-baseline.xml") // 基线,忽略已知问题
}
tasks.withType<Detekt>().configureEach {
reports {
html.required.set(true) // 生成 HTML 报告
xml.required.set(true)
}
}
自定义规则文件 detekt.yml 示例:
complexity:
TooManyFunctions:
active: true
threshold: 15
style:
WildcardImport:
active: false # 我个人允许通配符导入,看团队习惯
exceptions:
TooGenericExceptionCaught:
active: true
避坑指南:我曾经在一个项目里直接用了 Detekt 的默认配置,结果一跑,报了两百多个 warning。后来我学乖了,先建一个 baseline,把已有的问题标记为“已知”,然后逐步修复。这样不会阻塞开发进度。
14.4 Checkstyle:Java 代码的老牌守卫
如果你的项目里还有 Java 代码,Checkstyle 是绕不开的。它虽然“老”,但胜在稳定、规则丰富。
配置:
// build.gradle.kts
plugins {
checkstyle
}
checkstyle {
toolVersion = "10.17.0"
configFile = file("${rootDir}/config/checkstyle/checkstyle.xml")
maxErrors = 0 // 零容忍
maxWarnings = 10
}
tasks.withType<Checkstyle>().configureEach {
reports {
html.required.set(true)
}
}
一个简单的 checkstyle.xml 片段:
<module name="Checker">
<module name="TreeWalker">
<module name="AvoidStarImport"/>
<module name="IllegalCatch"/>
<module name="MagicNumber"/>
<module name="MissingJavadocMethod"/>
</module>
</module>
小技巧:Checkstyle 的规则文件写起来有点啰嗦。我一般从 Google 或 Sun 的官方配置里 copy 一份,然后删掉不想要的规则。别从头写,太累。
14.5 PMD:多语言静态分析
PMD 比 Checkstyle 更进一步,它能检测出潜在的 bug、未使用的变量、空的 catch 块等。支持 Java、Kotlin、Scala 等。
配置:
// build.gradle.kts
plugins {
pmd
}
pmd {
toolVersion = "7.1.0"
ruleSetFiles = files("${rootDir}/config/pmd/ruleset.xml")
ruleSets = listOf() // 清空默认规则集,只用自定义的
isIgnoreFailures = false // 失败就中断构建
}
tasks.withType<Pmd>().configureEach {
reports {
html.required.set(true)
}
}
规则集 ruleset.xml 示例:
<?xml version="1.0"?>
<ruleset name="Custom Rules">
<rule ref="category/java/bestpractices.xml">
<exclude name="GuardLogStatement"/>
</rule>
<rule ref="category/java/errorprone.xml"/>
<rule ref="category/java/performance.xml"/>
</ruleset>
注意:PMD 和 Detekt 有部分功能重叠。如果你项目全是 Kotlin,用 Detekt 就够了。如果是混合项目,PMD 管 Java,Detekt 管 Kotlin,分工明确。
14.6 工具集成与任务编排
这么多工具,总不能一个个手动跑吧?我们可以把它们编排到 Gradle 的生命周期里。
我的做法是这样的:
// 让 check 任务依赖所有质量检查
tasks.named("check") {
dependsOn(
tasks.named("spotlessCheck"),
tasks.named("detekt"),
tasks.named("checkstyleMain"),
tasks.named("pmdMain")
)
}
// 也可以单独定义一个 qualityCheck 任务
tasks.register("qualityCheck") {
dependsOn(
tasks.named("spotlessCheck"),
tasks.named("detekt"),
tasks.named("checkstyleMain"),
tasks.named("pmdMain")
)
group = "verification"
description = "运行所有代码质量检查"
}
这样,你只需要跑 ./gradlew check 或者 ./gradlew qualityCheck,所有工具就会按顺序执行。
14.7 整体架构图
下面这张图展示了这些工具在构建流程中的位置和关系:
14.8 一些实用建议
最后,分享几条我踩过坑之后总结的经验:
- 不要一次性开启所有规则。先开核心规则,跑通了再慢慢加。否则团队会炸毛。
- 把报告放在 CI 的 artifacts 里。这样谁都能看到,方便追溯。
- 定期更新工具版本。新版本通常会修复误报,增加新规则。
- 允许局部禁用。比如某些测试代码不需要严格检查,用
@Suppress或注释标记一下。
我曾经在一个项目里把 PMD 的规则开到了极致,结果构建时间从 2 分钟变成了 15 分钟。后来我学乖了,把一些耗时的规则(比如数据流分析)放到 nightly build 里,日常 CI 只跑轻量级检查。
好了,这一章的内容就到这里。代码质量工具配置好了,你的项目就有了“自动门卫”。接下来,你可以安心写业务逻辑,不用再为代码风格吵架了。