Code Review 实践指南

什么是 Code Review?

Code Review 就是团队成员互相看代码、给反馈的过程。研究表明,Code Review 可以找到约 65% 的错误。

为什么要做 Code Review?

1. 知识共享

  • 新人能从老手那学到经验
  • 了解项目的不同模块是怎么实现的
  • 避免”只有某个人懂某块代码”的情况
// ❌ 新人可能会这样写
function getUserData(userId) {
  return fetch(`/api/users/${userId}`)
    .then(res => res.json())
    .catch(err => console.log(err))
}

// ✅ Review 后的改进版本
async function getUserData(userId) {
  try {
    const response = await fetch(`/api/users/${userId}`)
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }
    return await response.json()
  } catch (error) {
    logger.error('Failed to fetch user data', { userId, error })
    throw error
  }
}

2. 提高代码质量

  • 多一双眼睛能发现更多问题
  • 知道别人会看,写代码时会更用心
  • 保持团队代码风格统一

3. 发现 Bug

  • 新的视角更容易发现问题
  • 边界情况、异常处理等容易被忽略的地方
  • 性能问题、安全隐患

4. 团队协作

  • 增进技术交流
  • 培养共同责任感
  • 形成良好的工程文化

什么时候做 Review?

提交前自查

提交代码前先自己过一遍:

  • 只提交相关的改动
  • 删掉调试代码和注释
  • 加上必要的测试
  • 更新相关文档
# 提交前看看改了啥
git diff --staged

PR Review(主要场景)

功能开发完、自测通过后,创建 Pull Request:

## PR 描述模板

### 改了什么
简单说明主要改动

### 相关 Issue
Closes #123

### 测试情况
- [ ] 单元测试通过
- [ ] 手动测试通过
- [ ] 测试场景:xxx

### 需要注意的点
列出需要 Reviewer 特别关注的地方

合并前最后检查

  • 至少 1 人 approve
  • 讨论都解决了
  • CI 都过了
  • 没有冲突

使用什么工具?

GitHub / GitLab(推荐)

最常用的 Code Review 平台:

  • 行级别的评论
  • 代码建议功能
  • CI/CD 集成
  • Review 状态管理

基本流程

# 1. 创建分支
git checkout -b feature/xxx

# 2. 开发、提交
git commit -m "feat: xxx"

# 3. 推送、创建 PR
git push origin feature/xxx

# 4. Review、修改、合并

自动化工具

让机器做能自动化的事:

# .github/workflows/pr-check.yml
name: PR Check
on: [pull_request]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Lint
        run: npm run lint
      - name: Test
        run: npm test

机器负责

  • 代码格式(Prettier, ESLint)
  • 跑测试
  • 测试覆盖率
  • 安全扫描

人负责

  • 业务逻辑对不对
  • 架构设计合不合理
  • 代码好不好读、好不好维护

Code Review 怎么做?

作为提交者

  1. 确保代码能跑

    npm test && npm run lint && npm run build
  2. 写清楚 PR 描述

    • 为什么做这个改动(比做了什么更重要)
    • 贴上相关文档或 Issue
    • 标注需要特别注意的地方
  3. 先自己 Review 一遍

    • 看看有没有无关的改动
    • 删掉临时代码和 TODO

作为 Reviewer

第一遍:看整体

  • 理解为什么要改这些
  • 整体架构合不合理
  • 改动范围是否合适

第二遍:看细节

功能逻辑

  • 逻辑正确吗?
  • 边界情况处理了吗?
  • 错误处理完善吗?

代码质量

  • 好读吗?
  • 有没有过度设计?
  • 有没有重复代码?

性能和安全

  • 有性能问题吗?
  • 有安全隐患吗?

怎么给反馈?

❌ 不好的评论:
"这里不对"

✅ 好的评论:
"这里用 map() 会创建新数组但没用到返回值,
建议用 forEach() 或 for...of,性能更好:

\`\`\`javascript
// 建议改成
items.forEach(item => processItem(item))
\`\`\`
"

原则

  • 🎯 对事不对人
  • 💡 说清楚为什么
  • 🤔 用疑问的语气:“是不是可以…”
  • 👍 好的地方也要表扬

反馈的优先级

用标签区分轻重:

  • 🔴 MUST:必须改
  • 🟡 SHOULD:强烈建议改
  • 🟢 NICE:可以改,锦上添花
  • 💭 QUESTION:有疑问,讨论一下
🔴 MUST: 这里会空指针,必须加 null 检查

🟡 SHOULD: 这个函数 100 多行了,建议拆分

🟢 NICE: 可以用 Optional 让代码更优雅

💭 QUESTION: 为啥用这个方案?考虑过 XXX 吗?

最佳实践

1. 控制 PR 大小

  • 每次不超过 400 行(Cisco 研究数据)
  • 太大的改动拆成多个 PR
  • 小的改动更容易发现问题
# 看看 PR 有多大
git diff --stat main...feature-branch

2. 及时 Review

  • 24 小时内开始 Review
  • 避免阻塞别人的工作
  • 趁着还记得,更好讨论

3. 用 Checklist

常用检查清单

  • 功能实现正确
  • 边界情况处理
  • 变量命名清晰
  • 没有重复代码
  • 性能没问题
  • 安全没漏洞
  • 有足够的测试

常见问题

❌ 橡皮图章

不看代码就点 Approve。

解决:至少要求留一条评论才能 approve

❌ 纠结细枝末节

花半天争论变量名,却忽略了严重的性能问题。

// 争论这个命名
const userData = getUserData()

// 却没发现这个 N+1 查询问题
users.forEach(user => {
  const orders = db.query(`SELECT * FROM orders WHERE user_id = ${user.id}`)
})

解决:用工具处理格式问题,人关注重要问题

❌ 过度设计

要求添加当前用不到的功能”万一以后要用呢”。

记住:YAGNI(You Aren’t Gonna Need It)

❌ 拖延

PR 堆了好几天没人看。

解决:把 Review 当成日常工作,设置提醒

❌ 情绪化评论

❌ "这什么垃圾代码?"
❌ "你连这个都不会?"

✅ "这里可能有性能问题,讨论一下更好的方案?"
✅ "考虑过用 XXX 模式吗?可能更合适"

流程图

graph TD
    A[开发完成] --> B{自我审查}
    B -->|通过| C[提交 PR]
    B -->|不通过| D[修改代码]
    D --> B
    C --> E{CI 检查}
    E -->|失败| D
    E -->|通过| F{同行审查}
    F -->|需要修改| G[讨论并修改]
    F -->|批准| H[合并代码]
    G --> F
    H --> I[结束]

总结

记住这几点

  1. ✅ 控制规模(不超过 400 行)
  2. ✅ 及时响应(24 小时内)
  3. ✅ 自动化工具(格式、测试交给机器)
  4. ✅ 建设性反馈(对事不对人)
  5. ✅ 持续改进(定期回顾)

避免这些坑

  1. ❌ 敷衍了事
  2. ❌ 纠结小事
  3. ❌ 拖延不看
  4. ❌ 情绪化评论

最重要的:Code Review 不是找茬,是一起把代码写得更好。

参考资料