代码重构不是推倒重来,而是在保持功能不变的前提下,把代码改得更易读、易维护。它不该是独立的"重构 sprint",而应融入日常开发。
1. 什么时候重构
- 添加新功能前:如果改一个地方要翻十层调用,先理顺再动手。
- 修复 Bug 后:把导致 Bug 的混乱逻辑顺手理清。
- Code Review 被指出的坏味道:过长函数、重复代码、魔法数字等。
- 不要重构:一次性脚本、即将废弃的模块、没有测试且没人懂的祖传代码(先补测试再动)。
2. 安全重构的前提
没有测试的重构就是走钢丝。 重构前至少保证:
- 核心流程能跑通(单元测试或手动冒烟测试)。
- 版本控制已提交,方便随时回滚。
- 一次只干一件事:需求代码和重构代码分两次提交,方便追责。
3. 最实用的几招
| 坏味道 | 重构手法 | 示例 |
|--------|----------|------|
| 函数超过 50 行 | 提取函数,用函数名解释意图 | calculate() → getUserDiscount() + applyTax() |
| 到处重复的代码 | 抽取公共方法/常量 | 把三处以上的相同逻辑抽到 utils 或父类 |
| 深层 if/else 嵌套 | 提前返回(卫语句) | if (!valid) return; 减少缩进 |
| 数字/字符串裸写 | 定义为常量/枚举 | status === 3 → status === OrderStatus.PAID |
| 一个类干所有事 | 按职责拆分 | 把数据校验、业务计算、网络请求拆到不同类/文件 |
| 注释解释代码在做什么 | 让代码自解释 | 用 isWeekend(date) 代替 // 判断是不是周末 |
4. 小步快跑,别贪大
- 每次只改一点:改完一个函数就运行测试,通过再继续。
- 命名是重构的核心:宁可名字长一点,也不要
handleData()这种万能命名。 - 不要追求"完美架构":先把 300 行的文件拆成 3 个 100 行的文件,就比原来好。
5. 真实世界的妥协
- 如果工期极紧,先记
TODO或建技术债卡片,别硬重构。 - 老系统重构时,遵循"绞杀者模式":新需求写新接口,老代码逐步代理过去,而非一次性替换。
- 重构后若发现性能下降,优先保证可读性;真的出现瓶颈时,再针对性优化热点代码。
总结:好的重构不会让代码瞬间变得高大上,而是让三个月后的自己(或同事)看一眼就能懂,改一行只动一处。