重构不是重写:识别坏味道,让代码越改越健康

软件项目有一个经典悖论:越到后期,加新功能越慢、修bug越多、团队越不敢动代码——直到某天有人提议“推倒重写”。而推倒重写的结局,大多是几年后新系统复刻了旧系统所有的坑。真正健康的代码库不是“从没写过烂代码”,而是被持续重构过:每次改动都顺手让结构变好一点点。重构,正是马丁·福勒1999年在《重构》里系统化的那门手艺。

重构的定义很严谨:在不改变代码外部行为的前提下,调整其内部结构。它不是重写、不是加功能,而是一系列“行为不变、结构变好”的小手术,比如提炼函数、重命名变量、消除重复。福勒有个著名的说法:重构降低了增强成本——代码库像一块地,重构是日常除草,而不是等它荒芜了再开垦。

技术债:重构真正要对付的是“利息”

“技术债”由沃德·坎宁安提出:为了赶进度写出“凑合能用”的代码,相当于借了一笔债。欠债本身不是错——有时就是该先上线再说;错的是无视利息。利息的表现很具体:每次在这块代码上改需求都要多花时间、bug集中出现在同一片区域、新人接手一周还看不懂结构。利息高过本金,就是该还债的信号。

反过来,判断“要不要现在重构”的标准也是利息:一段稳定运行、几乎不会再被改动的代码,债放着不产生利息,就不必急着还;而一个每周都在改、每次改都提心吊胆的模块,哪怕看起来还能跑,也到了该手术的时候。别为了重构而重构——重构服务于“未来的改动更便宜”,不是服务于代码洁癖。

坏味道:该动手的信号清单

福勒在书里整理了几十种“代码坏味道”,它们是重构的信号灯,最常遇到的几种:重复代码(改一处要追着改五处)、过长函数(一屏放不下,没人读得完)、过大的类(一个类管了八件事)、过长参数列霰弹式修改(一个需求要动十个文件)、依恋情结(一个方法总在摸别的类的数据)、夸夸其谈未来性(为不存在的需求提前写的抽象)。坏味道是症状,容易嗅到,背后往往是更深的结构问题。正确姿势是“闻到味再开刀”,而不是看哪里都不顺眼、凭感觉乱改。

重构的安全协议:小步、测试、随时可回滚

重构之所以被叫做“有纪律的技术”,是因为它有一套安全协议:

  • 每次只做一个行为不变的小变换:提炼一个函数、改一个名字、搬移一个方法,做完立刻跑测试,确认没改坏再继续下一步。
  • 没有测试的代码,先补测试再重构:测试是安全网,没有网的杂技不叫重构,叫冒险。核心模块尤其如此。
  • 小步前进、频繁提交:每一步都可回滚,出了问题是“撤销最近一步”,而不是深夜抢救。
  • 重构与功能改动分开提交:把“顺手重构”混进需求PR,出问题无法定位,评审也无法聚焦。行为不变的改动,单独成一次提交。

AI时代重构的执行者在变化:让AI按重构手法目录批量执行“提炼函数”“用卫语句取代嵌套条件”这类机械变换,人退到后面审查diff,效率提升显著。但原则不变——小步、有测试、行为不变。AI能加速“动手”,但“闻到坏味道”和“决定改哪里”依然依赖人的判断。

一个案例:三百行函数的拆分

一个支付模块里有个三百多行的函数,混着参数校验、折扣计算、优惠券核销和日志记录。每次需求变更,团队都在这个函数里小心翼翼地“挪动”,一个月内出了两次线上问题。重构是这样推进的:第一天先为它补上覆盖主要路径的单元测试,从红到绿;随后开始拆分——把参数校验提炼成独立方法,把折扣计算提取成策略对象,把日志逻辑抽离出去;每拆一步跑一次全量测试,全绿才动下一步。整个重构用了两个下午,函数从三百行降到四十行,每个职责各归其位。接下来的两周,团队在这个模块上连加了三个新需求,每个都在一小时内完成——而重构之前,类似的需求至少要半天。重构投入的时间,在第一个新需求上就全部回本了。

常见误区:把重构做坏的五个姿势

  • 把重构当重写:大爆炸式的“重构”本质是推倒重来,业务逻辑最容易在重写中悄悄丢失。真正的重构是几百个小变换的累积,每一步都可验证。
  • 没有测试硬重构:“行为不变”的保证来自测试,不来自自信。没有安全网的大改等于赌博。
  • 重构混进功能PR:一旦线上出问题,你无法判断是重构引入的还是功能引入的。两类改动严格分开提交。
  • 过度重构与投机性设计:为“未来可能用得上”提前抽象,本身就是一种坏味道。重构服务于当下的理解成本,不为想象的需求买单。
  • 只重构不预防:小步提交、清晰命名、及时清理这些日常习惯才是代码健康的根本。重构是补救手段,不是免死金牌。

行动建议

  1. 本周挑一个“每次改动都提心吊胆”的模块,先为它的核心路径补上单元测试。
  2. 用坏味道清单做一次自检,挑最明显的一种(重复代码或过长函数最常见),只做一个小重构:提炼或消除。
  3. 立下规矩:重构单独提交、与功能分开、每次提交前跑全量测试。
  4. 把“顺手清理”变成习惯:每次路过一段烂代码,至少做一件让情况变好一点的小事。代码库的健康,是攒出来的。

福勒有句话被引用最多:任何傻瓜都能写出计算机能看懂的代码,而好程序员写的是人能看懂的代码。重构就是让代码“被人看懂”的日常修炼——小步走、勤测试、随时停。别等系统烂透才想起它:重构最好的时机是昨天,其次是现在。

标签:#, #, #