refactoring
Installation
SKILL.md
大规模重构(Refactoring)
重构最大的风险不是改错,而是改了不知道影响了什么。 本 skill 的核心:先建安全网,再动刀子,每一步都有回退点。
第一步:判断是否需要本 skill
收到重构请求
│
├─ 改动 ≤2 个文件,不涉及公共接口?
│ └─ 直接动手,不需要本 skill
│
├─ 改动 3-5 个文件,局部重构?
│ └─ 走简化流程:第二步(快速版)→ 第四步 → 第五步
│
└─ 涉及公共接口 / 跨模块 / 架构调整 / 数据结构变更?
└─ 走完整流程:第二步 → 第三步 → 第四步 → 第五步 → 第六步
判断信号:
| 信号 | 走完整流程 |
|---|---|
| 改公共函数/类的签名 | 是 |
| 拆分或合并模块 | 是 |
| 改数据模型/数据库 schema | 是 |
| 改目录结构 | 是 |
| 改导入路径被多处引用 | 是 |
| 纯内部实现优化,接口不变 | 否,简化流程 |
第二步:影响分析
动手之前,先搞清楚"改这里会动到哪里"。
2.1 确定重构范围
- 重构目标:要改什么?改完应该是什么样?(用
AskUserQuestion和用户对齐) - 触发原因:为什么要重构?(技术债 / 性能 / 可维护性 / 新需求倒逼)
- 不改什么:明确哪些相关代码这次不动(防止 scope 膨胀)
2.2 依赖关系梳理
对要重构的模块,梳理上下游依赖:
被谁调用(上游)→ [重构目标] → 调用了谁(下游)
具体操作:
- Grep 搜索:搜索要重构的函数名/类名/模块路径,找到所有引用位置
- 导入分析:检查
import/require关系,画出依赖图 - 数据流追踪:如果涉及数据结构变更,追踪数据从哪来、到哪去
2.3 影响面评估
列出影响清单:
## 影响分析
### 直接影响(必须改)
- `src/services/auth.ts` — 调用了要重构的函数
- `src/api/user.ts` — 引用了要修改的类型
### 间接影响(需要验证)
- `src/pages/login.tsx` — 依赖 auth 服务,接口不变则不受影响
- `tests/auth.test.ts` — 测试用例需要同步更新
### 不受影响(确认安全)
- `src/utils/format.ts` — 无依赖关系
快速版(局部重构):只做 Grep 搜索确认引用范围,不需要完整的影响清单文档。
第三步:安全网搭建
没有安全网的重构是赌博。安全网 = 测试 + 回退能力。
3.1 确认现有测试覆盖
检查要重构的模块是否有测试:
# 找到相关测试文件
grep -r "重构目标函数名/模块名" tests/ __tests__/ *.test.* *.spec.*
| 现有测试情况 | 策略 |
|---|---|
| 有测试且覆盖核心路径 | 先跑通现有测试,确认 baseline 全绿 |
| 有测试但覆盖不足 | 补充关键路径测试后再开始重构 |
| 没有测试 | 必须先补测试,至少覆盖核心路径和边界情况 |
3.2 补充缺失测试
对于没有测试或覆盖不足的情况:
- 不需要追求 100% 覆盖率
- 重点覆盖:要改的函数的核心输入输出、公共接口的契约、边界情况
- 测试应该验证行为(输入→输出),不验证实现细节
- 把测试用例记录到
docs/tests/<模块名>-refactor.md
3.3 创建回退点
# 在重构开始前创建一个明确的 commit 或 branch
git checkout -b refactor/<模块名>
git commit -m "chore: 重构前基线 — 测试全绿"
确保随时可以 git diff refactor/<模块名> 看到所有改动,出问题能快速回退。
第四步:分步重构
大象要一口一口吃。每一步都是可验证的、可回退的。
4.1 制定重构计划
将重构拆分为独立的、可验证的小步骤,每步完成后测试应该通过:
## 重构计划
- [ ] Step 1: <描述> — 预期:测试全绿,行为不变
- [ ] Step 2: <描述> — 预期:测试全绿,行为不变
- [ ] Step 3: <描述> — 预期:测试全绿,新接口生效
- [ ] Step 4: 清理旧代码 — 预期:测试全绿,无废弃代码
拆分原则:
- 每步只做一件事(改结构不改逻辑 / 改逻辑不改结构)
- 每步改完都能编译通过、测试通过
- 步骤间尽量不互相依赖
- 危险操作(删代码、改数据结构)放后面,确认安全了再做
4.2 常用重构策略
| 场景 | 推荐策略 |
|---|---|
| 改公共接口签名 | 先新后删:新接口 → 迁移调用方 → 删旧接口 |
| 拆分大文件/大函数 | 提取 → 内联引用 → 验证 → 删旧 |
| 改目录结构 | 先移文件 → 修导入 → 验证 → 提交(单独一步,不混逻辑改动) |
| 替换依赖/框架 | 适配器模式:新旧共存 → 逐步迁移 → 移除旧依赖 |
| 改数据模型 | 双写过渡:新旧字段并存 → 迁移读写逻辑 → 清理旧字段 |
4.3 执行纪律
每完成一个步骤:
- 跑测试:确认现有测试全部通过
- 跑 lint:确认没有引入格式问题
- 快速 review:看一眼 diff,确认只改了该改的
- 提交:每步一个 commit,message 说清楚做了什么
git commit -m "refactor(auth): step 1 — 提取 token 验证为独立函数"
如果某一步测试挂了:
- 先看是不是测试本身需要更新(因为接口变了)
- 如果是意料之外的挂掉 → 停下来分析,不要硬继续
- 实在搞不清 → 回退到上一步的 commit,重新想策略
第五步:回归验证
重构的目标是"行为不变,结构更好"。验证行为是否真的没变。
5.1 运行全量测试
# 项目测试
npm test # 或 pytest
# 如果有 e2e 测试
npm run test:e2e
5.2 人工验证核心路径
测试不能覆盖一切。对于以下场景,手动验证:
- 页面渲染是否正常(前端重构)
- API 响应是否符合预期(后端重构)
- 关键业务流程走通(端到端)
5.3 对比验证
# 对比重构前后的 git diff,确认改动范围符合预期
git diff refactor/<模块名>..HEAD --stat
检查:
- 没有混入不相关的改动
- 没有遗留 debug 代码
- 没有遗留注释掉的旧代码
第六步:收尾
6.1 清理
- 删除废弃的旧代码(不是注释掉,是删掉)
- 更新相关文档(如果重构改了目录结构、接口、配置等)
- 更新
docs/tests/中的测试用例(重构过程中新增的测试要沉淀)
6.2 交给 task-finish 进行 CR 自检
重构完成后,交给 task-finish 执行深度自检:
- 改动范围是否符合重构目标?
- 有无混入不相关变更?
- 有无遗留调试代码?
6.3 复盘沉淀(由 task-manager 触发)
重构完成后,当用户将需求标 done 时,由 task-manager 触发复盘。重构类任务建议做完整复盘,记录到 docs/decisions/:
- 重构的动机和目标达成了吗?
- 哪些步骤顺利?哪些卡住了?
- 影响分析是否准确?遗漏了什么?
- 下次类似重构有什么经验可复用?
与其他 skill 的衔接
task-start
│ 判定为重构任务
↓
refactoring(本 skill)
│
├─ 第二步 ← dependency-map(影响分析,如果有的话)
├─ 第二步 ← writing(写重构方案,大型重构时)
├─ 第四步 ← task-execute(跨会话进度管理)
├─ 第五步 ← perf-profiling(性能相关重构时对比前后)
│
├─ 收尾 → task-finish(CR 自检)
└─ 需求标 done → task-manager → 触发复盘
反模式清单
| 反模式 | 后果 | 正确做法 |
|---|---|---|
| 没有安全网就开始改 | 改完不知道哪里坏了 | 先确认测试覆盖,再动手 |
| 一次改太多 | 出问题无法定位 | 小步提交,每步可验证 |
| 重构时顺手加功能 | scope 膨胀,风险叠加 | 重构和功能开发分开做 |
| 改结构的同时改逻辑 | 无法区分是结构改动还是逻辑改动引起的问题 | 一步只做一件事 |
| 注释掉旧代码不删 | 代码越来越脏 | 确认不用了就删 |
| 跳过回归测试 | 上线后才发现问题 | 每步跑测试,最后全量回归 |
| 不记录影响面 | 下次改同样的地方又不知道影响谁 | 影响分析写下来 |
Related skills