定义

重构(Refactoring):在不改变外部行为的前提下,改善代码的内部结构。

关键:行为不变是前提。如果重构改变了功能,那就不是重构,而是重写或改造——风险完全不同。

什么时候该重构

一、"三次法则"(Rule of Three)

第一次做某事,直接做;第二次,注意重复;第三次出现类似模式时,就该抽象和重构了。

过早抽象的代价(错误的抽象难以纠正)往往高于少量重复。

二、添加新功能之前

如果在混乱的代码上直接加功能,会让混乱加剧。

先重构,让它易于添加新功能,然后添加功能——这通常比"硬塞进去"更快,且质量更好。

(这被称为"预备性重构"。)

三、修复 bug 时

当你费了很大劲才理解某段代码时,正是重构的时机——把你的理解固化到代码结构中,下一个读它的人(可能是你自己)会轻松得多。

四、代码评审中发现问题

评审中指出的结构问题,应该在合并前解决。

五、当"债"开始拖慢速度时

如果你明显感觉到"在这个模块改东西特别慢",那就是信号。

什么时候不该重构

一、代码能正常工作、且很少改动。

重构有引入 bug 的风险。对稳定、低频修改的代码,收益可能不抵风险。

二、没有测试保护时,要谨慎。

重构的前提是能验证"行为不变"。如果没有测试,应该先补测试,再重构。

三、临近发布 deadline 时。

重构可能引入风险。大范围重构应该安排在发布窗口之外。

四、重写比重构更合适时。

如果代码的问题已经深入设计层面(而非局部结构),且模块边界清晰,重写可能是更好的选择——但重写的风险也很高,应该谨慎评估(尤其要避免"边重写边加新功能")。

怎么做才安全

一、小步前进。

每次只做一个小的改动,然后验证(跑测试)。

大爆炸式重构(一次改一大片)是事故高发区——一旦出问题,难以定位是哪一步引入的。

二、先有测试。

重构的安全网是自动化测试。没有测试时:

  • 先为现有行为编写 Characterization Tests(表征测试)——这些测试描述的是代码"现在实际做什么"(而非"应该做什么"),目的是捕捉行为,为重构提供保护;

三、利用工具。

现代 IDE 提供了安全的自动化重构:重命名、提取方法、提取变量、内联、移动……

优先使用 IDE 的自动重构,而不是手工编辑——工具不会遗漏引用,也不会打错字。

四、一次只做一件事。

要么重构(不改行为),要么改行为(不重构)。

混在一起时,如果出问题,你无法判断是重构引入的还是功能改动引入的。

常见重构手法

  • 提取方法(Extract Method):把长函数拆成几个小函数。
  • 重命名(Rename):改善命名——这是性价比最高的重构之一。
  • 提取变量/常量:给魔法数字和复杂表达式命名。
  • 内联(Inline):去掉不必要的间接层。
  • 以查询取代临时变量、以多态取代条件表达式、引入参数对象……

Martin Fowler 的《重构》一书系统整理了这些手法,是这一领域的经典。

一个提醒

重构需要得到团队和管理层的理解——因为它不产生"可见的新功能"。

沟通时强调它与业务目标的关联:更快的交付速度、更少的线上缺陷、更低的新人上手成本。

说明:本文为软件工程实践的知识整理。