4、重构原则:何时重构、何时不重构、重构的节奏与频率
重构这件事,说起来简单,做起来难。难的不是技术,而是判断——什么时候该动手,什么时候该忍住。
我见过不少团队,一听到重构就两眼放光,恨不得把整个系统推倒重来。也见过一些团队,代码烂到没法看了,还硬撑着说「能跑就行」。这两种极端,我都踩过坑。
这一章,咱们就聊聊重构的时机判断。说白了,就是帮你练就一双火眼金睛——知道什么时候该出手,什么时候该收手。
4.1 什么时候该重构?—— 三个信号
我个人习惯,把重构的时机归纳为三个信号。只要命中其中一个,我就会认真考虑动手。
| 信号 | 具体表现 | 我的判断标准 |
|---|---|---|
| 信号一:代码在「喊痛」 | 改一个功能,要动七八个文件;加一个新特性,得先读半小时代码才能找到入口 | 如果一次修改需要打开超过5个文件,就该警惕了 |
| 信号二:测试在「报警」 | 每次跑测试都要等很久,或者测试覆盖率越来越低,新代码几乎没测试 | 测试超过10分钟跑不完,我会先停下来看看是不是测试本身需要重构 |
| 信号三:团队在「抱怨」 | 代码评审时大家总在讨论「这段代码什么意思」,而不是「这段逻辑对不对」 | 如果代码评审超过30%的时间在解释代码意图,说明可读性出了问题 |
核心原则:重构不是为了「让代码更漂亮」,而是为了「让修改更安全、更快速」。如果代码已经影响到你的交付速度,那就是重构的信号。
4.2 什么时候不该重构?—— 三个陷阱
你想想看,重构也是有成本的。改代码、跑测试、回归验证,这些都要花时间。所以有些时候,我建议你忍住。
我曾经在一个项目里,花了整整两周重构一个模块。结果重构完才发现,这个模块下个月就要被替换掉了。嗯,那两周的时间,算是交了学费。
以下三种情况,我建议你暂时别动重构的念头:
- 陷阱一:代码即将被废弃 —— 如果这个模块已经有明确的替换计划,别碰它。最多加个注释,标记一下「此模块即将废弃」。
- 陷阱二:项目处于交付冲刺期 —— 离上线还有三天,你突然觉得代码「看着不顺眼」?忍住。这时候重构的风险远大于收益。
- 陷阱三:你还没理解这段代码 —— 如果你读了三遍还没看懂,别急着重构。先写测试,把行为锁定住。我曾经因为没理解透就动手,结果把一个隐藏的边界条件改坏了,线上出了bug。
避坑指南:我曾经在一个遗留系统上,看到一段200行的函数。我第一反应是「这必须拆」。但后来发现,这段代码虽然丑,但每个分支都有对应的业务场景。如果贸然拆开,反而会丢失上下文。所以,重构之前,先问自己一句:「我真的理解这段代码在做什么吗?」
4.3 重构的节奏与频率
重构不是一次性的「大扫除」,而应该是日常的「随手整理」。我建议你养成三个习惯:
4.3.1 小步提交,频繁重构
我个人习惯,每次修改不超过30分钟。如果30分钟搞不定,说明这个重构太大了,需要拆成更小的步骤。
举个例子:
// 重构前:一个函数干了三件事
function processOrder(order) {
// 验证订单
if (!order.id || !order.items.length) {
throw new Error('Invalid order');
}
// 计算总价
let total = 0;
for (let item of order.items) {
total += item.price * item.quantity;
}
// 发送通知
sendEmail(order.userEmail, `Your total is ${total}`);
return total;
}
// 重构后:拆成三个小函数
function validateOrder(order) { /* ... */ }
function calculateTotal(order) { /* ... */ }
function notifyUser(order, total) { /* ... */ }
function processOrder(order) {
validateOrder(order);
const total = calculateTotal(order);
notifyUser(order, total);
return total;
}
你看,每次只做一件事。改完一个函数,跑一遍测试,确认没问题,再改下一个。这样即使出问题,也能快速定位。
4.3.2 与功能开发交替进行
我不建议专门安排一个「重构月」。更好的做法是:每开发两个新功能,就花一点时间重构相关的旧代码。
说白了,就是「边修路边开车」。你不需要把整条路都封了再修,而是开一段,修一段。
我的经验:我习惯在每天的代码提交前,花15分钟做一次「小重构」。比如重命名一个变量、提取一个方法、删除一段死代码。这些小事积累起来,效果非常明显。
4.3.3 用「技术债务」来管理
我建议团队维护一个「技术债务清单」。每次发现需要重构的地方,就记下来,标注优先级和预估工时。
这样做的目的是:让重构变得可管理、可追踪。而不是靠某个人「灵光一现」才想起来去改。
4.4 知识体系:重构决策流程图
下面这张图,是我自己总结的重构决策流程。每次犹豫要不要重构时,我就拿出来看一眼。
这张图的逻辑很简单:三个问题,只要有一个答案是「是」,就暂时别动。三个都是「否」,那就放心大胆地重构吧。
4.5 重构的频率:找到你的节奏
重构的频率没有标准答案。但我可以分享一个经验:
- 日常重构(每天):重命名、提取方法、删除死代码。每次不超过15分钟。
- 任务级重构(每次功能开发):在开发新功能时,顺手重构相关的旧代码。每次不超过1小时。
- 迭代级重构(每个迭代):每个迭代结束时,花半天时间处理技术债务清单上的高优先级项。
记住:重构不是目的,而是手段。你的目标是让代码更容易修改、更容易理解。如果重构做不到这一点,那就别做。
嗯,这一章的内容就到这里。重构的时机判断,说白了就是三个字:看情况。但有了这些原则和流程,你至少不会在错误的时间做错误的事。