第一章:重构入门——什么是重构?为什么需要重构?重构与重写的区别

1.1 重构到底是什么?

先问大家一个问题:你写代码的时候,有没有过这样的经历——

一段代码跑得好好的,功能也没问题,但你就是看着它别扭。变量名像天书,函数长到能绕地球三圈,if 嵌套比俄罗斯套娃还深。你想改,又怕改出 bug。不改吧,每次维护都像在拆弹。

嗯,这就是重构要解决的问题。

重构,说白了就是在不改变代码外部行为的前提下,改善其内部结构。注意关键词:不改变外部行为。也就是说,用户看到的、系统输出的结果,必须和重构前一模一样。你改的是代码的“内功”,不是“招式”。

我个人习惯把重构比作“整理房间”。房间还是那个房间,家具也没换位置,但你把杂物归了类,把灰尘擦了擦,把电线理了理。住起来舒服了,找东西快了,心情也好了。代码也是一样。

核心定义:重构 = 改善设计 + 保持行为不变

1.2 为什么需要重构?

你可能要问:代码能跑不就行了?折腾它干嘛?

我在项目中遇到过太多次这样的场景:一个模块,三个月没人动,突然要加个新功能。打开一看,好家伙,一个函数 500 行,变量名全是 a、b、c、temp。你花了两天看懂它,又花了一天小心翼翼地改,最后测试还挂了。为什么?因为代码的“坏味道”已经让它的可维护性降到了冰点。

重构的必要性,我总结为三点:

  • 降低维护成本——干净的代码,改起来快,出 bug 的概率低。脏代码,改一行崩三处。
  • 提升可读性——你写的代码,不只是给机器看的,更是给人看的。三个月后的你,也是“别人”。
  • 暴露隐藏的缺陷——重构过程中,你会重新审视逻辑,很多潜藏的 bug 会自己跳出来。我曾经在重构一个支付模块时,发现了一个金额精度问题,差点酿成大祸。

我的经验:重构不是“没事找事”,而是“防患于未然”。代码的腐化速度比你想象的要快。一个项目如果半年不做任何重构,基本就进入了“改不动”的状态。

1.3 重构 vs 重写:别搞混了

这是新手最容易混淆的两个概念。我见过太多团队,把“重构”当成了“重写”的借口,结果项目延期、需求变更、老板发火……

来,直接看对比:

维度 重构 重写
行为变化 不改变外部行为 可能改变外部行为
风险等级 低(小步快跑) 高(推倒重来)
时间成本 可控(按小时计) 不可控(按周/月计)
业务影响 几乎无影响 可能中断业务
适用场景 代码结构差,但逻辑正确 架构过时,或技术栈淘汰

你想想看,重写就像把房子拆了重建。地基、水电、墙体全换。而重构呢?只是重新刷个墙、换个地板、理一理电线。哪个风险大?一目了然。

我曾经接手过一个 Node.js 项目,代码乱到连作者自己都看不懂。团队里有人提议“干脆重写吧”。我拦住了。为什么?因为业务逻辑极其复杂,重写意味着要重新理解所有需求,重新测试所有边界情况。那段时间,我们花了三周做重构,每天只改一小块,每改完就跑一遍完整的测试用例。三周后,代码干净了,功能一个没少,线上零故障。

如果当时选择了重写,我估计三个月都未必能上线。

避坑指南:我曾经见过一个团队,把“重构”挂在嘴边,结果干的是“重写”的活。项目延期半年,老板差点砍掉整个部门。记住:重构是手术,重写是投胎。别动不动就想投胎。

1.4 什么时候该重构?什么时候该重写?

这个问题没有标准答案,但我可以给你几个判断依据:

  • 代码有测试覆盖吗?有,可以重构。没有,先补测试,再重构。没有测试的重构,等于闭着眼开车。
  • 业务逻辑还在快速变化吗?是,建议重构。因为重写跟不上变化速度。
  • 技术栈是否已被官方废弃?是,考虑重写。比如 Node.js 12 以下的版本,该升级了。
  • 团队对现有代码的理解程度如何?几乎为零?那重写可能比重构更省力。但前提是你得先搞清楚业务需求。

说白了,重构是日常,重写是最后的手段。我个人的习惯是:每次修改代码时,顺手做一点重构。比如改一个函数时,顺手把变量名改得更清晰;加一个功能时,顺手把重复的代码抽成公共方法。这叫“童子军规则”——让营地比你发现时更干净。

1.5 一个小例子:重构前后的对比

来看一段 Node.js 代码,典型的“坏味道”:

// 重构前
function handleUser(data) {
  let a = data.name;
  let b = data.age;
  let c = data.email;
  if (a && b && c) {
    console.log('Name: ' + a + ', Age: ' + b + ', Email: ' + c);
    // 50 行后续逻辑...
  }
}

这段代码的问题很明显:变量名无意义、函数职责不单一、字符串拼接丑陋。重构后:

// 重构后
function printUserInfo(user) {
  const { name, age, email } = user;
  if (!name || !age || !email) {
    return;
  }
  console.log(`Name: ${name}, Age: ${age}, Email: ${email}`);
}

看到了吗?行为完全没变——输入输出一模一样。但代码的可读性、可维护性提升了不止一个档次。这就是重构的力量。

小技巧:重构时,每次只做一件事。改完一个变量名,就跑一遍测试。改完一个函数拆分,就跑一遍测试。步子越小,风险越低。

1.6 总结

重构不是炫技,不是“代码洁癖”,而是一种工程纪律。它让你的代码保持健康,让你的团队保持高效,让你的项目活得更久。

记住三句话:

  • 重构是改善内部结构,不改变外部行为。
  • 重构是日常,重写是最后手段。
  • 没有测试的重构,就是耍流氓。

下一章,我会带你看看重构的“坏味道”清单——哪些代码信号在告诉你:该重构了。

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