name: 代码审查 description: 系统化地审查拉取请求、功能实现和代码更改,以确保质量、可维护性、安全性,并遵循最佳实践。用于在合并前审查代码、进行同行评审、执行自我审查、审计代码质量、检查安全漏洞、确保一致的编码标准、验证测试覆盖、评估性能影响、评估架构决策,或提供建设性反馈以提高团队代码质量。
代码审查 - 系统化代码质量分析
何时使用此技能
- 在合并到主分支前审查拉取请求
- 为团队成员进行同行代码审查
- 在提交代码审查前进行自我审查
- 审计代码质量和标准合规性
- 检查安全漏洞和不良实践
- 验证足够的测试覆盖存在
- 评估更改的性能影响
- 评估架构和设计决策
- 确保与项目编码标准的一致性
- 提供建设性反馈以提高代码质量
- 审查关键业务逻辑或敏感操作
- 检查常见反模式和代码异味
何时使用此技能
- 在合并前审查拉取请求、功能实现或代码更改,以确保质量、可维护性,并遵循最佳实践。
- 当处理相关任务或功能时
- 在需要此专业知识的开发过程中
使用时机:在合并前审查拉取请求、功能实现或代码更改,以确保质量、可维护性,并遵循最佳实践。
核心原则
- 先理解后审查 - 在建议更改前,确保理解意图和上下文
- 具体且可操作 - 指向具体行并提供具体建议
- 平衡优点与改进 - 承认良好模式的同时建议改进
- 关注影响 - 优先处理关键问题(安全、正确性)而非风格偏好
- 教育而非纠正 - 解释更改为何重要
审查清单
1. 正确性与逻辑
✓ 代码是否实现了其声称的功能?
✓ 是否处理了边缘情况(空值、空集、边界值)?
✓ 是否存在潜在的竞态条件或时序问题?
✓ 错误处理是否恰当和完整?
✓ 假设是否经过验证?
2. 安全性
✓ 对所有用户提供的数据进行输入验证?
✓ SQL注入、XSS、CSRF保护措施?
✓ 秘密/凭证是否正确保护(环境变量,非硬编码)?
✓ 身份验证和授权检查?
✓ 公共端点的速率限制?
3. 性能
✓ N+1查询问题?
✓ 不必要的数据库调用或API请求?
✓ 内存泄漏(事件监听器、订阅)?
✓ 对大数据集正确分页?
✓ 高效算法(在可能时避免O(n²),使用O(n log n))?
4. 可维护性
✓ 变量/函数名称清晰、描述性强?
✓ 函数单一职责(只做好一件事)?
✓ DRY - 无复制粘贴重复?
✓ 魔术数字替换为命名常量?
✓ 复杂逻辑用注释解释?
5. 测试
✓ 测试覆盖正常路径和错误情况?
✓ 测试是确定性的(无不稳定测试)?
✓ 边缘情况已测试?
✓ 集成点适当模拟/存根?
✓ 测试名称描述其验证内容?
6. 代码风格与标准
✓ 与项目约定一致?
✓ 遵循语言习惯?
✓ 无未使用导入或死代码?
✓ 正确抛出/返回错误类型?
✓ TypeScript类型具体(非'any')?
审查流程
步骤1:高级审查
1. 阅读PR描述和链接问题
2. 理解更改背后的"原因"
3. 扫描文件列表 - 范围是否匹配描述?
4. 检查缺失文件(测试、迁移、文档)
步骤2:深度代码审查
1. 先审查关键路径(安全、数据完整性)
2. 检查测试覆盖和质量
3. 查找架构问题
4. 审查错误处理
5. 检查性能问题
步骤3:提供反馈
格式:[严重性] 问题 - 具体建议
示例:
[CRITICAL] 第45行的SQL注入漏洞
- 使用参数化查询而非字符串拼接
- 更改:`query = f"SELECT * FROM users WHERE id = {user_id}"`
- 至:`query = "SELECT * FROM users WHERE id = ?"` 带参数
[SUGGESTION] 考虑将这个50行的函数拆分为更小部分
- 第100-150行可以拆分为:
- `validateInput()`(第100-120行)
- `processData()`(第121-140行)
- `formatOutput()`(第141-150行)
反馈严重性级别
- [CRITICAL] - 安全问题、数据丢失风险、功能损坏
- [MAJOR] - 性能问题、错误处理不当、逻辑错误
- [MINOR] - 代码异味、可维护性问题、风格不一致
- [SUGGESTION] - 可选改进、替代方法
- [PRAISE] - 值得强调的良好模式
示例代码审查
拉取请求:添加用户身份验证端点
审查评论:
[CRITICAL] 密码更改端点缺少身份验证(第67行)
// 当前 - 无身份验证检查
app.post('/change-password', (req, res) => {
const { userId, newPassword } = req.body;
updatePassword(userId, newPassword);
});
// 应该是:
app.post('/change-password', requireAuth, (req, res) => {
// 仅允许用户更改自己的密码
if (req.user.id !== req.body.userId) {
return res.status(403).json({ error: '禁止' });
}
const { newPassword } = req.body;
updatePassword(req.user.id, newPassword);
});
[MAJOR] 密码在存储前未哈希(第23行)
// 从不存储明文密码
await db.users.update({ password: req.body.password }); // ❌
// 使用bcrypt或argon2
const hashedPassword = await bcrypt.hash(req.body.password, 10);
await db.users.update({ passwordHash: hashedPassword }); // ✅
[MINOR] 令牌过期的魔术数字(第45行)
const token = jwt.sign(payload, secret, { expiresIn: 3600 }); // ❌
// 使用命名常量
const TOKEN_EXPIRY_SECONDS = 60 * 60; // 1小时
const token = jwt.sign(payload, secret, { expiresIn: TOKEN_EXPIRY_SECONDS }); // ✅
[PRAISE] 优秀的输入验证(第12-20行) 这里的zod模式全面,包括所有必要检查。这防止了畸形数据到达数据库。
常见反模式标记
1. 静默失败
// 坏 - 错误消失
try {
await criticalOperation();
} catch (e) {
console.log('哎呀'); // ❌
}
// 好 - 正确处理错误
try {
await criticalOperation();
} catch (e) {
logger.error('关键操作失败', { error: e, context: {...} });
throw new CriticalOperationError('处理失败', { cause: e });
}
2. 回调地狱 / 金字塔厄运
// 坏
getData((data) => {
processData(data, (result) => {
saveResult(result, (saved) => {
// 3+层级深 ❌
});
});
});
// 好 - 使用async/await
const data = await getData();
const result = await processData(data);
const saved = await saveResult(result);
3. 上帝函数
// 坏 - 函数做太多事
function handleUserRequest(req) {
// 200行验证、处理、格式化、保存 ❌
}
// 好 - 拆分职责
function handleUserRequest(req) {
const validated = validateRequest(req);
const processed = processUserData(validated);
const formatted = formatResponse(processed);
return saveAndRespond(formatted);
}
何时阻止 vs 带评论批准
阻止合并(请求更改):
- 安全漏洞
- 数据丢失风险
- 功能损坏
- 缺少关键测试
- 主要性能问题
带评论批准:
- 风格改进
- 重构建议
- 次要性能优化
- 文档增强
- 可选测试
自动化检查
在手动审查前,确保自动化检查通过:
✓ 代码检查(ESLint、Pylint等)
✓ 类型检查(TypeScript、mypy)
✓ 单元测试通过
✓ 集成测试通过
✓ 代码覆盖达到阈值
✓ 安全扫描(SAST)
✓ 依赖漏洞扫描
审查响应模板
## 总结
[PR的高级评估]
## 关键问题
- [列出阻止问题]
## 主要关注点
- [列出重要但非阻止问题]
## 建议
- [列出可选改进]
## 积极亮点
- [指出良好模式]
## 问题
- [关于意图或方法的澄清问题]
## 批准状态
- [ ] 批准 - 准备合并
- [ ] 带次要评论批准
- [ ] 请求更改 - 阻止问题需解决
资源
记住:目标是在保持团队士气的同时提高代码质量。要彻底但尊重、具体但不挑剔,并始终解释建议背后的“原因”。