# 第十阶段 · 模块十 · 第二节:代码重构实战
如何使用 Claude Code 进行代码重构?/simplify 命令的完整流程是什么?如何确保重构的安全性?
Claude Code 全局架构
┌─────────────────────────────────────────────────────────────────────┐
│ 实战案例 │
│ │
│ 代码重构实战 ← 本节 │
│ ├── /simplify 命令 │
│ ├── 三阶段审查 │
│ └── 重构安全策略 │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 重构(Refactoring) │
│ │
│ 定义:改善代码结构而不改变其行为 │
│ │
│ 与修复 Bug 的区别: │
│ - 重构:不改变功能,改进结构 │
│ - 修复 Bug:改变行为,修复错误 │
└─────────────────────────────────────────────────────────────────────┘
源码位置:`src/skills/bundled/simplify.ts`
// /simplify 命令 = 代码审查 + 重构
// 功能:
// 1. 代码复用审查
// 2. 代码质量审查
// 3. 效率审查
// 特点:
// - 自动修复发现的问题
// - 三阶段并行审查
问 1:什么时候应该重构?
// 应该重构:
// - 代码重复
// - 函数过长
// - 难以理解
// - 难以测试
// 不应该重构:
// - 代码已经稳定
// - 重构风险过高
// - 短期要废弃的代码
# 简化当前更改
claude /simplify
# 指定焦点
claude /simplify 专注于性能优化
源码位置:`src/skills/bundled/simplify.ts`
┌─────────────────────────────────────────────────────────────────────┐
│ Phase 1: 识别更改 │
│ 运行 git diff 查看变更 │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Phase 2: 三阶段并行审查 │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Agent 1 │ │ Agent 2 │ │ Agent 3 │ │
│ │ 代码复用审查 │ │ 代码质量审查 │ │ 效率审查 │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Phase 3: 修复问题 │
│ 汇总发现并直接修复 │
└─────────────────────────────────────────────────────────────────────┘
问 1:为什么使用三个 Agent 并行审查?
// 并行审查的优势:
// 1. 速度
// - 三个审查并行执行
// - 比串行快 3 倍
// 2. 专注
// - 每个 Agent 专注一个领域
// - 避免交叉干扰
// 3. 全面
// - 同时覆盖多个维度
// - 不会遗漏问题
源码位置:`src/skills/bundled/simplify.ts`
// Agent 1: Code Reuse Review
// 审查点:
// 1. 搜索现有工具
// - utility 目录
// - 共享模块
// - 相邻文件
// 2. 标记重复功能
// - 新函数是否已有实现
// - 建议使用现有函数
// 3. 标记内联逻辑
// - 字符串处理
// - 路径处理
// - 环境检查
// 问题示例:
// ❌ 不好:手写字符串处理
const parts = str.split(',').map(s => s.trim())
// ✅ 好:使用现有工具
import { splitAndTrim } from '@utils/string'
const parts = splitAndTrim(str)
问 1:如何找到可以复用的代码?
// 方法:
// 1. 搜索关键词
// - "util"
// - "helper"
// - "common"
// 2. 查看相邻文件
// - 同目录下的工具文件
// - 同包内的共享模块
// 3. 询问 Claude
// "这个逻辑有没有现有的实现?"
源码位置:`src/skills/bundled/simplify.ts`
// Agent 2: Code Quality Review
// 审查点:
// 1. 冗余状态
// - 重复的 state
// - 可以推导的缓存值
// 2. 参数蔓延
// - 函数参数过多
// - 应该泛化或重构
// 3. 复制粘贴变体
// - 相似的代码块
// - 应该统一抽象
// 4. 泄露抽象
// - 暴露内部细节
// - 破坏抽象边界
// 5. 字符串类型
// - 使用原始字符串
// - 应该使用常量或枚举
// 6. 不必要的 JSX 嵌套
// 7. 不必要的注释
// 问题示例:
// ❌ 冗余状态
const [items, setItems] = useState([])
const [filteredItems, setFilteredItems] = useState([]) // 可以推导
// ✅ 好:派生状态
const filteredItems = useMemo(() =>
items.filter(...), [items])
// ❌ 字符串类型
if (type === 'user') // magic string
// ✅ 好:使用常量
if (type === UserType.User)
问 1:什么时候应该统一抽象?
// 应该统一抽象:
// - 三个或更多相似实现
// - 行为相同,细节不同
// - 未来可能继续变化
// 不应该统一抽象:
// - 只有两个相似实现
// - 未来可能分化
// - 抽象会带来复杂性
源码位置:`src/skills/bundled/simplify.ts`
// Agent 3: Efficiency Review
// 审查点:
// 1. 不必要的工作
// - 冗余计算
// - 重复文件读取
// - N+1 模式
// 2. 错过的并发
// - 独立操作顺序执行
// - 可以并行化
// 3. 热路径膨胀
// - 启动时的阻塞
// - 每次请求的处理
// 4. 不必要的存在检查
// - TOCTOU 反模式
// - 直接操作,处理错误
// 5. 内存问题
// - 无界数据结构
// - 事件监听器泄漏
// 6. 过度宽泛的操作
// - 读取整个文件
// - 加载所有项目
// 问题示例:
// ❌ N+1 查询
for (const user of users) {
const posts = await getPosts(user.id)
}
// ✅ 好:批量查询
const userIds = users.map(u => u.id)
const posts = await getPostsByUserIds(userIds)
// ❌ 每次渲染都读取文件
const config = readFileSync('config.json') // 阻塞
// ✅ 好:缓存
const config = useMemo(() =>
readFileSync('config.json'), [])
问 1:如何避免 N+1 查询?
// N+1 查询 = 循环中每次查询
// 解决方法:
// 1. 批量查询
// - 收集所有 ID
// - 一次查询
// 2. JOIN 查询
// - 在数据库层合并
// 3. 缓存
// - 使用 DataLoader 模式
// 重构前检查:
// 1. 确保有测试
// - 单元测试
// - 集成测试
// 2. 备份
// - git commit
// - 或创建备份分支
// 3. 理解代码
// - 阅读相关测试
// - 理解依赖关系
// 重构中原则:
// 1. 小步前进
// - 每次只改一件事
// - 提交频繁
// 2. 保持测试通过
// - 每次修改后运行测试
// - 不要积累大量更改
// 3. 保持可逆
// - 如果出错,容易回滚
问 1:如何确保重构不破坏功能?
// 方法:
// 1. 测试驱动重构
// - 先写测试
// - 然后重构
// 2. 渐进式重构
// - 每次改一点
// - 频繁运行测试
// 3. 对比测试
// - 重构前后行为对比
// - 确保输出一致
// 原始代码
function processUserInput(input: string): string[] {
const trimmed = input.trim()
const parts = trimmed.split(',')
const result: string[] = []
for (const part of parts) {
result.push(part.trim())
}
return result
}
Agent 1 (代码复用):
- 发现手写的 split + trim
- 建议使用 @utils/string 包的 splitAndTrim
Agent 2 (代码质量):
- 可以简化为一行
- 参数名可以更清晰
Agent 3 (效率):
- 性能良好,无需优化
// ✅ 重构后
import { splitAndTrim } from '@utils/string'
function processUserInput(input: string): string[] {
return splitAndTrim(input, ',')
}
问 1:重构前后代码行为一致吗?
// 测试验证:
// input: " a, b , c "
// 重构前: ["a", "b", "c"]
// 重构后: ["a", "b", "c"]
// ✅ 一致
答案:
// 重构(Refactoring):
// - 改善结构,不改变行为
// - 渐进式,小步前进
// - 保持测试通过
// 重写(Rewrite):
// - 重新实现,从头开始
// - 大爆炸,一次完成
// - 风险更高
答案:
// 考虑重写的场景:
// 1. 代码库太小
// - 重写比重构更快
// 2. 架构彻底错误
// - 重构无法解决
// 3. 技术过时
// - 无法找到维护者
// 4. 需求根本改变
// - 现有代码不适用
答案:
// 说服策略:
// 1. 量化问题
// - "这个函数有 500 行"
// - "每次修改需要 2 小时理解"
// 2. 展示收益
// - "重构后修改只需 10 分钟"
// - "测试覆盖率从 30% 提升到 80%"
// 3. 降低风险
// - "小步前进"
// - "有测试保护"
// - "可以随时停止"
| 资源 | 说明 |
| /simplify 命令 | 代码审查 + 重构 |
| /review 命令 | 代码审查 |
| Martin Fowler《重构》 | 经典参考书 |
下一节我们将深入 Bug 修复实战:
- Bug 分析方法
- 调试技巧
- 修复验证
*- 第一轮:□ 事实准确性*
*- 第二轮:□ 深度与洞见*
*- 第三轮:□ 可读性与价值*