--- name: code-refactor description: 基于 Martin Fowler 方法论的系统化代码重构 skill。适用于用户请求重构代码、改进代码结构、减少技术债、清理旧代码、消除 code smell 或提升可维护性时。这个 skill 采用分阶段、带研究与计划的安全增量实施方式。 --- # 代码重构 Skill 这是一个基于 Martin Fowler《Refactoring: Improving the Design of Existing Code》(第 2 版)的系统化代码重构方法。这个 skill 强调安全、渐进的修改,并由测试提供保障。 > “重构是在不改变软件外部行为的前提下,改进其内部结构的过程。” — Martin Fowler ## 核心原则 1. **保持行为不变**:外部行为必须保持一致 2. **小步前进**:每次只做很小、可测试的改动 3. **测试驱动**:测试是安全网 4. **持续进行**:重构是长期过程,不是一次性任务 5. **协作确认**:每个阶段都需要用户确认 ## 工作流程总览 ``` 阶段 1:研究与分析 ↓ 阶段 2:测试覆盖评估 ↓ 阶段 3:识别代码异味 ↓ 阶段 4:创建重构计划 ↓ 阶段 5:增量实施 ↓ 阶段 6:评审与迭代 ``` --- ## 阶段 1:研究与分析 ### 目标 - 理解代码库结构和用途 - 确定重构范围 - 收集业务需求背景 ### 先向用户确认的问题 开始前先确认: 1. **范围**:哪些文件 / 模块 / 函数需要重构? 2. **目标**:你想解决什么问题?(可读性、性能、可维护性) 3. **约束**:有哪些区域不能改? 4. **时间压力**:这是否阻塞了其他工作? 5. **测试状态**:是否已有测试?是否通过? ### 行动 - [ ] 阅读并理解目标代码 - [ ] 识别依赖和集成点 - [ ] 记录当前架构 - [ ] 标记已有技术债迹象(TODO、FIXME) ### 输出 向用户汇报: - 代码结构总结 - 识别出的问题区域 - 初步建议 - **请求继续执行的批准** --- ## 阶段 2:测试覆盖评估 ### 为什么测试重要 > “没有测试的重构,就像没有安全带就开车。” — Martin Fowler 测试是安全重构的**关键前提**。没有测试,很容易引入 bug。 ### 评估步骤 1. **检查现有测试** ```bash # 查找测试文件 find . -name "*test*" -o -name "*spec*" | head -20 ``` 2. **运行现有测试** ```bash # JavaScript / TypeScript npm test # Python pytest -v # Java mvn test ``` 3. **检查覆盖率(如果可用)** ```bash # JavaScript npm run test:coverage # Python pytest --cov=. ``` ### 决策点:询问用户 **如果测试存在且通过:** - 进入阶段 3 **如果测试缺失或不完整:** 给出选项: 1. 先写测试(推荐) 2. 在重构过程中逐步补测试 3. 不写测试直接继续(有风险,需要用户确认) **如果测试失败:** - 停止。先修复失败测试再重构 - 问用户:是否先修测试? ### 测试编写建议(如需要) 对每个要重构的函数,测试应覆盖: - 正常路径 - 边界情况(空输入、null、边界值) - 错误场景(非法输入、异常) 使用“红-绿-重构”循环: 1. 写失败测试(红) 2. 让它通过(绿) 3. 再重构 --- ## 阶段 3:识别代码异味 ### 什么是代码异味? 代码深层问题的表面症状。它们不一定是 bug,但说明代码设计可能有问题。 ### 常见异味清单 完整目录见 [references/code-smells.md](references/code-smells.md)。 #### 快速参考 | 异味 | 迹象 | 影响 | |-------|------|------| | **长函数** | 函数超过 30-50 行 | 难以理解、测试和维护 | | **重复代码** | 多处出现相同逻辑 | 修复需要改多处 | | **大类** | 类承担了太多职责 | 违反单一职责原则 | | **Feature Envy** | 一个方法更多依赖别的类的数据 | 封装性差 | | **基础类型沉迷** | 过度使用基础类型而不是对象 | 缺少领域概念 | | **长参数列表** | 方法参数超过 4 个 | 调用困难 | | **数据泥团** | 一组数据总是一起出现 | 缺少抽象 | | **switch 语句** | 复杂的 switch / if-else 链 | 难以扩展 | | **臆想泛化** | “以防未来需要”提前设计 | 不必要的复杂度 | | **死代码** | 未使用的代码 | 造成困惑和维护负担 | ### 分析步骤 1. **自动分析**(如果有脚本) ```bash python scripts/detect-smells.py ``` 2. **人工审查** - 系统地走读代码 - 记录每个异味的位置和严重性 - 按影响分类(Critical / High / Medium / Low) 3. **优先级排序** 优先关注会: - 阻塞当前开发的异味 - 导致 bug 或混淆的异味 - 影响最常变更代码路径的异味 ### 输出:异味报告 向用户呈现: - 识别出的异味及位置 - 每项的严重性评估 - 建议的优先级顺序 - **请求用户确认优先级** --- ## 阶段 4:创建重构计划 ### 选择重构方式 针对每个异味,从目录中选择合适的重构手法。 完整列表见 [references/refactoring-catalog.md](references/refactoring-catalog.md)。 #### 异味到重构的映射 | 代码异味 | 推荐重构 | |----------|----------| | 长函数 | Extract Method、Replace Temp with Query | | 重复代码 | Extract Method、Pull Up Method、Form Template Method | | 大类 | Extract Class、Extract Subclass | | Feature Envy | Move Method、Move Field | | 基础类型沉迷 | Replace Primitive with Object、Replace Type Code with Class | | 长参数列表 | Introduce Parameter Object、Preserve Whole Object | | 数据泥团 | Extract Class、Introduce Parameter Object | | switch 语句 | Replace Conditional with Polymorphism | | 臆想泛化 | Collapse Hierarchy、Inline Class、Remove Dead Code | | 死代码 | Remove Dead Code | ### 计划结构 使用 [templates/refactoring-plan.md](templates/refactoring-plan.md) 里的模板。 每项重构都要写明: 1. **Target**:将修改哪些代码 2. **Smell**:解决什么问题 3. **Refactoring**:采用哪种手法 4. **Steps**:详细微步骤 5. **Risks**:可能出什么问题 6. **Rollback**:如何回退 ### 分阶段方法 **关键**:重构必须分阶段推进。 **阶段 A:快速收益**(低风险,高价值) - 重命名变量以提升清晰度 - 提取明显重复的代码 - 删除死代码 **阶段 B:结构改进**(中风险) - 从长函数中提取方法 - 引入参数对象 - 把方法移动到更合适的类 **阶段 C:架构改动**(高风险) - 用多态替代条件分支 - 提取类 - 引入设计模式 ### 决策点:把计划展示给用户 在开始实施前: - 展示完整重构计划 - 解释每个阶段及其风险 - 获得每个阶段的明确批准 - **询问**:“是否继续执行阶段 A?” --- ## 阶段 5:增量实施 ### 黄金法则 > “修改 → 测试 → 通过?→ 提交 → 下一步” ### 实施节奏 对每一步重构: 1. **预检查** - 测试通过(绿色) - 代码能编译 2. **只做一个小改动** - 按目录中的具体操作进行 - 保持改动最小化 3. **验证** - 立刻运行测试 - 检查编译错误 4. **如果测试通过(绿色)** - 用描述清晰的提交信息提交 - 继续下一步 5. **如果测试失败(红色)** - 立刻停止 - 撤销改动 - 分析原因 - 如有疑问,询问用户 ### 提交策略 每次提交都应当: - **原子性**:只包含一个逻辑改动 - **可回滚**:容易撤销 - **描述清楚**:提交信息明确 示例提交信息: ``` refactor: 从 processOrder() 中提取 calculateTotal() refactor: 将 'x' 重命名为 'customerCount' 以提升清晰度 refactor: 删除未使用的 validateOldFormat() 方法 ``` ### 进度汇报 每个子阶段完成后,向用户汇报: - 做了哪些改动 - 测试是否仍通过 - 遇到了什么问题 - **询问**:“继续下一批吗?” --- ## 阶段 6:评审与迭代 ### 重构后检查清单 - [ ] 所有测试通过 - [ ] 没有新的警告 / 错误 - [ ] 代码编译成功 - [ ] 行为没有变化(手动验证) - [ ] 必要时已更新文档 - [ ] 提交历史干净 ### 指标对比 重构前后运行复杂度分析: ```bash python scripts/analyze-complexity.py ``` 展示改进: - 代码行数变化 - 圈复杂度变化 - 可维护性指标变化 ### 用户评审 向用户展示最终结果: - 所有变更摘要 - 重构前后代码对比 - 指标改善情况 - 剩余技术债 - **询问**:“你对这些改动满意吗?” ### 下一步 和用户讨论: - 还要处理哪些异味? - 是否安排下一次重构? - 是否把类似修改应用到其他地方? --- ## 重要指南 ### 何时暂停并询问 遇到以下情况时,务必暂停并和用户确认: - 不确定业务逻辑 - 改动可能影响外部 API - 测试覆盖不足 - 需要做重大的架构决策 - 风险上升 - 遇到意外复杂性 ### 安全规则 1. **没有测试不要重构**(除非用户明确确认风险) 2. **不要做大改动**,拆成小步 3. **每次改动后都不要跳过测试** 4. **测试失败就不要继续**,先修复或回滚 5. **不要臆测**,不确定就问 ### 不要做什么 - 不要把重构和新功能混在一起 - 不要在生产事故期间做重构 - 不要重构你看不懂的代码 - 不要过度设计,保持简单 - 不要一次性重构所有内容 --- ## 快速上手示例 ### 场景:长函数 + 重复逻辑 **重构前:** ```javascript function processOrder(order) { // 150 行代码,包含: // - 重复验证逻辑 // - 内联计算 // - 多种职责混杂 } ``` **重构步骤:** 1. **确认测试存在**,覆盖 `processOrder()` 2. **提取** 验证逻辑为 `validateOrder()` 3. **测试** - 应该通过 4. **提取** 计算逻辑为 `calculateOrderTotal()` 5. **测试** - 应该通过 6. **提取** 通知逻辑为 `notifyCustomer()` 7. **测试** - 应该通过 8. **评审** - `processOrder()` 现在只负责串联 3 个清晰函数 **重构后:** ```javascript function processOrder(order) { validateOrder(order); const total = calculateOrderTotal(order); notifyCustomer(order, total); return { order, total }; } ``` --- ## 参考资料 - [代码异味目录](references/code-smells.md) - 代码异味完整清单 - [重构目录](references/refactoring-catalog.md) - 重构手法 - [重构计划模板](templates/refactoring-plan.md) - 计划模板 ## 脚本 - `scripts/analyze-complexity.py` - 分析代码复杂度指标 - `scripts/detect-smells.py` - 自动检测 code smell ## 版本历史 - v1.0.0 (2025-01-15):首次发布,包含 Fowler 方法论、分阶段流程和用户确认点