CodeRoad Map 程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。
由 程序员柏风 独立维护 · 关于作者
学习 更多
代码风格
这一课你将能做到
用 Checkstyle / Spotless / ESLint 把风格问题拦截在 Review 之前
识别「风格争议」和「真正的代码异味」之间的区别
在团队内推动「机器管风格,人管设计」的分工
为什么要学
Code Review 最浪费时间的事,就是人工争论「这里该不该加空格」「import 顺序对不对」。这些应该全部交给机器。人审的精力留给真正需要判断的事:设计、语义、边界。
人话:让 linter 当坏人,reviewer 当导师。机器卡格式,人来看思路。
先建立图像
Review 时间分配
┌────────────────────────────────────────┐
│ 风格问题(空格/换行/import 顺序) │
│ → 100% 交给 Lint 工具 │
│ Checkstyle / Spotless / ESLint │
│ Reviewer 看到 = Lint 配置不全 │
├────────────────────────────────────────┤
│ 命名 / 函数长度 / 嵌套深度 │
│ → Lint 管一部分(规则化) │
│ → Reviewer 管一部分(需要语境判断) │
├────────────────────────────────────────┤
│ 设计 / 抽象 / 边界 / 语义 │
│ → 100% 人来审 │
└────────────────────────────────────────┘
跟着做
步骤 1:配置 Checkstyle(Java 后端)
pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<configLocation>google_checks.xml</configLocation>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
</configuration>
<executions>
<execution>
<phase>validate</phase>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>
效果:mvn compile 时自动检查,风格不达标直接编译失败。
步骤 2:配置 Spotless(自动格式化)
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.43.0</version>
<configuration>
<java>
<googleJavaFormat>
<version>1.22.0</version>
<style>GOOGLE</style>
</googleJavaFormat>
<removeUnusedImports/>
<trimTrailingWhitespace/>
<endWithNewline/>
</java>
</configuration>
</plugin>
mvn spotless:apply # 一键格式化整个项目
配合 pre-commit hook,提交前自动跑。
步骤 3:配置 ESLint + Prettier(前端)
// .eslintrc.json
{
"extends": [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/consistent-type-imports": "error",
"no-console": ["warn", { "allow": ["warn", "error"] }],
"react-hooks/exhaustive-deps": "error"
}
}
// .prettierrc
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 100
}
package.json 加 lint-staged:
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,css}": ["prettier --write"]
}
}
步骤 4:识别 Lint 管不了的「代码异味」 Lint 能管空格、import、行长。这些它管不了,但 reviewer 必须管:
❌ 反例 1:函数过长(Lint 可配,但很多团队不配)
public void processOrder(OrderReq req) {
// 200 行业务逻辑全堆在这
}
public void processOrder(OrderReq req) {
validateOrder(req);
Order order = buildOrder(req);
deductStock(order);
processPayment(order);
notifyUser(order);
}
if (user != null) {
if (user.isVip()) {
if (order.getAmount() > 100) {
if (coupon != null) {
// 真正逻辑在第 5 层
}
}
}
}
if (user == null) return;
if (!user.isVip()) return;
if (order.getAmount() <= 100) return;
if (coupon == null) return;
// 真正逻辑在顶层
if (user.getStatus() == 3 && days > 90) { ... }
if (user.getStatus() == UserStatus.VIP && days > VIP_TRIAL_DAYS) { ... }
步骤 5:处理「风格争议」
用 4 空格还是 2 空格缩进?
大括号换不换行?
import 用 * 还是全展开?
团队风格决议(示例)
- Java: Google Java Format(2 空格缩进,100 列)
- TypeScript: Prettier 默认 + 单引号 + 尾逗号 es5
- import 禁止 *
- 未使用变量 = error(CI 直接挂)
决议方式:团队投票,多数决。
执行方式:Spotless / Prettier 自动格式化 + CI 强校验。
后续争议:不提 PR 讨论风格,只提 PR 改配置文件。
讲清楚要点
风格问题 100% 交给机器 :人审风格是浪费生命。任何 lint 能管的事,都不该出现在 PR 评论里。
Lint 配置是团队契约 :一旦定了,写进配置文件,CI 强校验,谁都别想绕。比任何文档都管用。
Reviewer 关注 Lint 管不了的 :函数长度、嵌套深度、命名、抽象层级——这些需要语境判断。
自动化胜过文档 :「我们的代码规范见 wiki 第 3 章」不如 mvn spotless:apply。
别在 PR 里翻案风格 :觉得某条规则不合理?提个 PR 改配置文件,全项目统一调整。别在业务 PR 里夹带私货。
你可能会懵的地方
老项目接入 Lint 会爆出几千个问题怎么办?
分阶段:① 先跑一次 spotless:apply 全量格式化(单独一个 PR,纯格式化无逻辑改动);② CI 开启强校验;③ 后续增量代码自动符合规范。一次性做完,不要拖。
格式化工具和 IDE 冲突怎么办?
IDE 配置 import 项目的 style 文件(如 intellij-java-google-style.xml),保证「IDE 自动格式化」和「CI 校验」结果一致。否则每次保存都会产生无意义 diff。
Reviewer 就是觉得某个命名不好,但 Lint 不管,怎么办?
可以提,但说清楚理由(「这个 data 太泛了,改成 courseList 更明确」),别只说「感觉不好」。如果作者坚持,尊重作者——命名偏好是主观的。
Prettier 和 ESLint 怎么分工?
Prettier 管格式(空格、换行、引号),ESLint 管代码质量(未用变量、错误用法)。用 eslint-config-prettier 关闭 ESLint 里和 Prettier 冲突的格式规则。
Checkstyle 规则太严想放宽某条?
改配置文件,不要加 @SuppressWarnings。配置文件是团队契约,注解是个体行为——后者会导致规范形同虚设。
错法对照 错法 问题 正解 PR 评论里争论空格 浪费时间 配 Lint,机器卡 函数 200 行 无法测试、无法理解 按职责拆分,单函数 < 30 行 嵌套 5 层 if 逻辑路径爆炸 卫语句提前返回 魔法数字 语义不明 提取常量 @SuppressWarnings 到处都是规范形同虚设 改配置文件统一调整
卡点急救
CI 上 Lint 挂了但本地没挂 :检查本地是不是用了不同的 JDK 版本 / Maven 版本 / Node 版本。用 .nvmrc、maven-enforcer-plugin 锁定版本。
Spotless 和 IDE 格式化结果不一致 :导入 Spotless 用的同一份 style 文件到 IDE;或者干脆关闭 IDE 自动格式化,提交前手动 mvn spotless:apply。
老代码不想全量格式化(怕引入冲突) :用 Spotless 的 ratchetFrom 功能,只对增量代码校验。但强烈建议全量格式化一次到位,长痛不如短痛。
面试常问
团队如何统一代码风格?
三步:① 选定公开标准(Google Java Format / Airbnb JS Style)或自定义;② 配置自动化工具(Checkstyle/Spotless/ESLint/Prettier)+ CI 强校验;③ pre-commit hook 让开发者在本地提前发现。关键是「机器执行」而不是「人记规范」。
函数应该多长?
没有标准答案。经验值:单个函数一屏能看完(20-40 行),单函数只做一件事。更重要的是「函数内部的代码在同一个抽象层级」——一个函数里既有 user.getName() 又有字节级位运算,就是抽象层级混乱。
怎么处理 reviewer 和作者的风格分歧?
规则化的事听 lint 的;非规则化的事(命名、函数拆分)作者有最终决定权,reviewer 可以建议但不强制。如果 reviewer 坚持认为有问题,升级到团队讨论,产出新的团队约定。不要让 PR 卡住超过一天只为风格争论。
自测三问
为什么说「风格问题应该 100% 交给机器」?
Lint 管不了的代码异味有哪些?各举一例。
老项目接入 Lint 的最佳路径是什么?
小结一句话 代码风格的终极目标是「不再讨论风格」——用机器执行统一标准,把人的精力留给真正需要判断的事。
延伸