选择一个你熟悉的领域(前端代码、API 设计、SQL 查询、文档写作),创建一个审查 Skill。
Level 1:创建你自己的审查 Skill要求:
- 至少包含 3 个检查维度
- 每个维度有 3-5 个具体检查项
- 输出格式清晰(通过、需注意、必须修复)
- 测试至少 2 个实际案例
学习目标:
- 学习如何组织多步骤工作流
- 理解检查清单模式的应用
- 掌握 supporting files 的使用
- 创建一个生产可用的复杂 Skill
代码审查是典型的结构化工作流:1
这个案例会展示:
开始写之前,先确定这个 Skill 要检查什么。
我们的代码审查 Skill 检查三个维度:
不检查的内容:
这次我们用 supporting files 来组织审查规则:2
为什么要拆分文件:
checklists/naming.md:
checklists/error-handling.md:
准备一段有多个问题的代码:
调用 Skill:
预期输出应该包含:
process, data, x, y 都太泛化var 而不是 const/let== 而不是 ===data 是否为 null 或不是数组item.value 是否存在第一次运行可能会发现:
持续改进:
下一课,我们学习进阶技巧:personal vs project skills、版本控制、团队协作。
Anthropic 工程博客:Agent Skills 实战指南 — https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills ↩
Anthropic Platform 文档:Agent Skills 概述 — https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview ↩ ↩2
Claude Code Skills:.NET 工作流与可复用提示 — https://codewithmukesh.com/blog/skills-claude-code/ ↩
要求:
对比两者发现的问题,记录:
Jot down thoughts, sticking points, things you didn't get. Written to this course's appendix only — the lesson file is never touched.
mkdir -p ~/.claude/skills/code-review
mkdir -p ~/.claude/skills/code-review/checklists
touch ~/.claude/skills/code-review/SKILL.md
touch ~/.claude/skills/code-review/checklists/naming.md
touch ~/.claude/skills/code-review/checklists/error-handling.md
---
name: code-review
description: 审查代码变更,检查命名规范、错误处理、潜在 bug 和可维护性问题。用于 PR 审查或代码质量检查
---
# 代码审查助手
系统化审查代码变更,基于团队规范和最佳实践。
## 输入格式
接受以下任何格式:
- Git diff 输出
- 完整的代码文件
- 代码片段(函数或类)
- PR 链接(需要先用工具读取 PR 内容)
## 审查流程
按以下顺序执行审查:
### 1. 代码规范检查
参考 `checklists/naming.md`,逐项检查:
- **变量命名**:是否使用有意义的名字、是否符合团队命名约定(驼峰、下划线等)
- **函数命名**:动词开头、清楚表达意图
- **类命名**:名词、符合单一职责原则
- **常量命名**:全大写、下划线分隔
**标准:** 所有命名应该让不熟悉代码的人也能理解其用途
### 2. 错误处理检查
参考 `checklists/error-handling.md`,检查:
- **异常捕获**:是否有 try-catch、是否捕获了正确的异常类型
- **错误返回值**:函数是否正确处理和传播错误
- **边界情况**:空输入、null、undefined、空数组等是否处理
- **资源清理**:文件、连接、锁等是否正确释放
**标准:** 任何可能失败的操作都应该有错误处理
### 3. 潜在问题检查
- **空指针/未定义访问**:是否有可能访问不存在的属性或方法
- **类型安全**:是否有隐式类型转换风险
- **并发问题**:是否有竞态条件、死锁风险
- **安全漏洞**:SQL 注入、XSS、CSRF、敏感信息泄露
**标准:** 任何可能导致运行时错误或安全风险的代码都标记出来
### 4. 可维护性检查
- **函数长度**:超过 50 行的函数建议拆分
- **重复代码**:相似逻辑出现 3 次以上建议提取
- **嵌套深度**:超过 3 层嵌套建议重构
- **注释质量**:复杂逻辑是否有注释解释
**标准:** 代码应该容易被其他开发者理解和修改
## 输出格式
按以下结构输出审查结果:
### ✅ 通过的检查
- [检查项] - 符合标准
### ⚠️ 需要注意的问题
- **位置**:`文件名:行号`
- **问题**:具体是什么问题
- **影响**:可能导致什么后果
- **建议**:如何改进
### 🔴 必须修复的问题
- **位置**:`文件名:行号`
- **问题**:具体是什么问题
- **风险**:为什么必须修复
- **建议**:具体的修复方案
### 📊 总体评估
- 代码质量:优秀 / 良好 / 需改进
- 主要问题:[总结最重要的 2-3 个问题]
- 建议优先级:[哪些问题应该先修复]
## 注意事项
- **上下文理解**:如果代码片段不完整,说明可能需要更多上下文
- **框架特性**:某些看起来的"问题"可能是框架的特定用法,标注为"需确认"
- **测试代码**:测试代码的标准可以适当放宽(如函数长度)
- **无问题时**:如果所有检查都通过,输出"✅ 代码审查通过,未发现明显问题"
# 命名规范检查清单
## 变量命名
**好的命名:**
- `userCount`:清楚表达是用户的数量
- `isAuthenticated`:布尔值用 is/has/can 开头
- `maxRetryAttempts`:常量说明了含义和单位
**不好的命名:**
- `x`, `temp`, `data`:太泛化
- `flag`, `status`:不说明具体是什么状态
- `getUserInfo2`:有数字后缀说明可能有重复
## 函数命名
**好的命名:**
- `calculateTotalPrice()`:动词+名词,清楚表达动作和对象
- `validateUserInput()`:说明了做什么和作用于什么
- `fetchUserProfile()`:fetch 表明这是异步操作
**不好的命名:**
- `process()`:太泛化,不知道处理什么
- `doStuff()`:完全不表达意图
- `handleData()`:handle 和 data 都太宽泛
## 类命名
**好的命名:**
- `UserRepository`:名词,表达了职责(用户数据存取)
- `PaymentProcessor`:清楚说明是处理支付的
- `EmailValidator`:说明了验证邮箱的职责
**不好的命名:**
- `Manager`, `Helper`, `Utility`:太泛化的后缀
- `DataClass`:不说明具体是什么数据
# 错误处理检查清单
## 必须检查的场景
### 1. 外部依赖调用
- API 请求(网络失败、超时、4xx/5xx 响应)
- 数据库查询(连接失败、查询超时、约束违反)
- 文件操作(文件不存在、权限不足、磁盘满)
### 2. 用户输入
- 空输入、null、undefined
- 格式不正确
- 超出范围的值
### 3. 数据转换
- JSON 解析(格式错误)
- 类型转换(字符串转数字失败)
- 日期解析(无效日期格式)
## 错误处理模式
**捕获并处理:**
```javascript
try {
const data = await fetchUser(id);
return processData(data);
} catch (error) {
logger.error('Failed to fetch user', { id, error });
return null; // 或抛出自定义错误
}
```
**检查后调用:**
```javascript
if (!user) {
throw new Error('User not found');
}
const profile = user.getProfile(); // 安全,user 不是 null
```
## 常见错误
**问题:** 空 catch 块
```javascript
try {
riskyOperation();
} catch (e) {
// 什么都不做 - 问题:错误被吞掉了
}
```
**修复:** 至少要记录日志
```javascript
try {
riskyOperation();
} catch (e) {
logger.error('Operation failed', e);
throw e; // 或返回错误状态
}
```
function process(data) {
var result = [];
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item.type == "A") {
var x = item.value * 2;
result.push(x);
} else if (item.type == "B") {
var y = item.value / 2;
result.push(y);
} else {
result.push(item.value);
}
}
return result;
}
/code-review
[粘贴上面的代码]