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 知识体系:重构决策流程图

下面这张图,是我自己总结的重构决策流程。每次犹豫要不要重构时,我就拿出来看一眼。

重构决策流程图 发现一段「不舒服」的代码 Q1: 这段代码是否即将被废弃? (是否有明确的替换计划?) ❌ 不重构 加注释标记即可 Q2: 是否处于交付冲刺期? (离上线还有几天?) ❌ 不重构 记入技术债务清单 Q3: 是否理解这段代码的全部行为? (是否有测试覆盖?) 先写测试,再考虑重构 ✅ 可以开始重构

这张图的逻辑很简单:三个问题,只要有一个答案是「是」,就暂时别动。三个都是「否」,那就放心大胆地重构吧。

4.5 重构的频率:找到你的节奏

重构的频率没有标准答案。但我可以分享一个经验:

  • 日常重构(每天):重命名、提取方法、删除死代码。每次不超过15分钟。
  • 任务级重构(每次功能开发):在开发新功能时,顺手重构相关的旧代码。每次不超过1小时。
  • 迭代级重构(每个迭代):每个迭代结束时,花半天时间处理技术债务清单上的高优先级项。

记住:重构不是目的,而是手段。你的目标是让代码更容易修改、更容易理解。如果重构做不到这一点,那就别做。

嗯,这一章的内容就到这里。重构的时机判断,说白了就是三个字:看情况。但有了这些原则和流程,你至少不会在错误的时间做错误的事。

公众号:蓝海资料掘金营,微信 deep3321