大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
代码风格
这一课你将能做到
- 用 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);
}
❌ 反例 2:嵌套过深
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;
// 真正逻辑在顶层
❌ 反例 3:魔法数字
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 的最佳路径是什么?
小结一句话
代码风格的终极目标是「不再讨论风格」——用机器执行统一标准,把人的精力留给真正需要判断的事。
延伸
- Google Java Style
- Spotless Maven Plugin
- Prettier
- 下一课:Review 流程——PR 大小与审查节奏。