代码评审(Code Review)

中级 Intermediate 流程型 Process ⚡ Claude Code 专属 ⚡ Claude Code Optimized
6 min read · 286 lines

置信度过滤 + 严重等级分类,评审聚焦真正重要的问题

来源: everything-claude-code by Affaan Mustafa 原始文件: agents/code-reviewer.md + commands/code-review.md

代码评审(Code Review)

概述

一套系统化的代码评审流程,包含安全审查、代码质量检查和最佳实践验证。通过置信度过滤和严重等级分类,确保评审结果聚焦于真正重要的问题,避免噪音干扰。适合在每次代码修改后立即使用。

二、评审清单

安全问题(CRITICAL -- 严重)

以下问题必须标记 -- 它们可能造成真正的损害:

  • 硬编码凭据(Hardcoded credentials) -- 源代码中的 API 密钥、密码、令牌(Token)、连接字符串
  • SQL 注入(SQL injection) -- 查询中使用字符串拼接而非参数化查询
  • XSS 漏洞(XSS vulnerabilities) -- 未转义的用户输入渲染在 HTML/JSX 中
  • 路径遍历(Path traversal) -- 未经清理的用户控制文件路径
  • CSRF 漏洞(CSRF vulnerabilities) -- 状态修改端点(Endpoint)缺少 CSRF 防护
  • 身份验证绕过(Authentication bypasses) -- 受保护路由缺少身份验证检查
  • 不安全的依赖(Insecure dependencies) -- 已知有漏洞的软件包
  • 日志中暴露敏感信息(Exposed secrets in logs) -- 记录敏感数据(令牌、密码、个人身份信息)
// 错误:通过字符串拼接导致 SQL 注入
const query = `SELECT * FROM users WHERE id = ${userId}`;

// 正确:参数化查询
const query = `SELECT * FROM users WHERE id = $1`;
const result = await db.query(query, [userId]);
// 错误:未经清理就渲染原始用户 HTML
// 始终使用 DOMPurify.sanitize() 或等效方法清理用户内容

// 正确:使用文本内容或进行清理
<div>{userComment}</div>

代码质量(HIGH -- 高)

  • 过长函数(>50 行)-- 拆分为更小、更专注的函数
  • 过大文件(>800 行)-- 按职责提取模块
  • 深层嵌套(>4 层)-- 使用提前返回(Early return)、提取辅助函数
  • 缺少错误处理 -- 未处理的 Promise 拒绝、空 catch 块
  • 可变模式(Mutation patterns) -- 优先使用不可变操作(展开运算符、map、filter)
  • console.log 语句 -- 合并前移除调试日志
  • 缺少测试 -- 新代码路径没有测试覆盖
  • 死代码(Dead code) -- 注释掉的代码、未使用的导入、不可达的分支
// 错误:深层嵌套 + 可变操作
function processUsers(users) {
  if (users) {
    for (const user of users) {
      if (user.active) {
        if (user.email) {
          user.verified = true;  // 可变操作!
          results.push(user);
        }
      }
    }
  }
  return results;
}

// 正确:提前返回 + 不可变 + 扁平结构
function processUsers(users) {
  if (!users) return [];
  return users
    .filter(user => user.active && user.email)
    .map(user => ({ ...user, verified: true }));
}

React/Next.js 模式(HIGH -- 高)

审查 React/Next.js 代码时,还需检查:

  • 缺少依赖数组 -- useEffect/useMemo/useCallback 的依赖不完整
  • 渲染中更新状态(State updates in render) -- 渲染期间调用 setState 会导致无限循环
  • 列表缺少 key -- 当项目可以重新排序时使用数组索引作为 key
  • 属性透传(Prop drilling) -- 属性传递超过 3 层(应使用 Context 或组合模式)
  • 不必要的重新渲染 -- 对昂贵计算缺少记忆化(Memoization)
  • 客户端/服务端边界 -- 在服务端组件(Server Components)中使用 useState/useEffect
  • 缺少加载/错误状态 -- 数据获取没有回退 UI
  • 过期闭包(Stale closures) -- 事件处理器捕获了过期的状态值
// 错误:缺少依赖,过期闭包
useEffect(() => {
  fetchData(userId);
}, []); // userId 缺失于依赖列表中

// 正确:完整的依赖
useEffect(() => {
  fetchData(userId);
}, [userId]);
// 错误:使用索引作为 key,列表可重新排序
{items.map((item, i) => <ListItem key={i} item={item} />)}

// 正确:稳定的唯一 key
{items.map(item => <ListItem key={item.id} item={item} />)}

Node.js/后端模式(HIGH -- 高)

审查后端代码时:

  • 未验证的输入 -- 请求体/参数未经 Schema 验证就使用
  • 缺少速率限制(Rate limiting) -- 公开端点没有限流
  • 无限制查询 -- 面向用户的端点使用 SELECT * 或没有 LIMIT 的查询
  • N+1 查询 -- 在循环中获取关联数据而非使用 JOIN/批量查询
  • 缺少超时配置 -- 外部 HTTP 调用没有超时设置
  • 错误信息泄露 -- 向客户端发送内部错误详情
  • 缺少 CORS 配置 -- API 可被意外的来源访问
// 错误:N+1 查询模式
const users = await db.query('SELECT * FROM users');
for (const user of users) {
  user.posts = await db.query('SELECT * FROM posts WHERE user_id = $1', [user.id]);
}

// 正确:使用 JOIN 或批量查询
const usersWithPosts = await db.query(`
  SELECT u.*, json_agg(p.*) as posts
  FROM users u
  LEFT JOIN posts p ON p.user_id = u.id
  GROUP BY u.id
`);

性能(MEDIUM -- 中)

  • 低效算法 -- 可以用 O(n log n) 或 O(n) 时却使用了 O(n^2)
  • 不必要的重新渲染 -- 缺少 React.memo、useMemo、useCallback
  • 过大的包体积(Bundle size) -- 导入整个库而非使用可摇树(Tree-shakeable)的替代方案
  • 缺少缓存 -- 重复的昂贵计算没有记忆化
  • 未优化的图片 -- 大图片没有压缩或懒加载
  • 同步 I/O -- 在异步上下文中执行阻塞操作

最佳实践(LOW -- 低)

  • TODO/FIXME 没有关联工单 -- TODO 应引用 Issue 编号
  • 公共 API 缺少 JSDoc -- 导出的函数没有文档
  • 命名不佳 -- 在非简单上下文中使用单字母变量(x、tmp、data)
  • 魔法数字(Magic numbers) -- 未解释的数字常量
  • 格式不一致 -- 混合使用分号、引号风格、缩进

三、评审命令(Command)

快速评审流程

对未提交变更进行全面的安全和质量审查:

  1. 获取变更文件:git diff --name-only HEAD

  2. 对每个变更文件,检查:

    安全问题(CRITICAL -- 严重):

    • 硬编码的凭据、API 密钥、令牌
    • SQL 注入漏洞
    • XSS 漏洞
    • 缺少输入验证
    • 不安全的依赖
    • 路径遍历风险

    代码质量(HIGH -- 高):

    • 函数超过 50 行
    • 文件超过 800 行
    • 嵌套深度超过 4 层
    • 缺少错误处理
    • console.log 语句
    • TODO/FIXME 注释
    • 公共 API 缺少 JSDoc

    最佳实践(MEDIUM -- 中):

    • 可变模式(应使用不可变方式)
    • 代码/注释中使用 Emoji
    • 新代码缺少测试
    • 无障碍性(a11y)问题
  3. 生成报告,包含:

    • 严重等级:CRITICAL、HIGH、MEDIUM、LOW
    • 文件位置和行号
    • 问题描述
    • 建议修复方案
  4. 如果发现 CRITICAL 或 HIGH 问题,阻止提交

绝不批准含有安全漏洞的代码!


四、评审输出格式

按严重等级组织评审结果。对于每个问题:

[CRITICAL] 源代码中硬编码了 API 密钥
文件: src/api/client.ts:42
问题: API 密钥 "sk-abc..." 暴露在源代码中。这将被提交到 git 历史记录中。
修复: 移至环境变量并添加到 .gitignore/.env.example

  const apiKey = "sk-abc123";           // 错误
  const apiKey = process.env.API_KEY;   // 正确

评审摘要格式

每次评审结束时输出:

## 评审摘要

| 严重等级 | 数量 | 状态 |
|----------|------|------|
| CRITICAL | 0    | 通过 |
| HIGH     | 2    | 警告 |
| MEDIUM   | 3    | 信息 |
| LOW      | 1    | 备注 |

结论: 警告 -- 2 个 HIGH 问题应在合并前解决。

五、审批标准

  • 批准(Approve):无 CRITICAL 或 HIGH 问题
  • 警告(Warning):仅有 HIGH 问题(可谨慎合并)
  • 阻止(Block):发现 CRITICAL 问题 -- 必须在合并前修复

六、项目特定指南

在可用时,还应检查来自 CLAUDE.md 或项目规则的项目特定约定:

  • 文件大小限制(例如:典型 200-400 行,最大 800 行)
  • Emoji 策略(许多项目禁止在代码中使用 Emoji)
  • 不可变性要求(展开运算符优于修改操作)
  • 数据库策略(RLS、数据库迁移模式)
  • 错误处理模式(自定义错误类、错误边界)
  • 状态管理约定(Zustand、Redux、Context)

根据项目已建立的模式调整你的评审。如有疑问,与代码库的其余部分保持一致。

相关技能 Related Skills