重构做一半停手,代价比想象大
去年有一版代码我改到一半,被一个更急的活插进来,就搁下了。三周后回去看,那段代码一半是新写法、一半是老写法,我自己都分不清哪个是哪个。那次之后我才搞明白,重构做了一半停下来会更糟吗——答案不是「会不会更糟」,是「你到底停在哪一步」。
最贵的一课就一句话:重构的真正代价不在改的时候,在停的时候。
一、坑一:停在「两套写法并存」的中间态
代码重构最危险的状态不是旧代码,是新旧各占一半。
老代码虽然难看,但它自洽——函数怎么调、数据怎么流,是一整套。你改了一半之后,一部分走新路径、一部分走老路径,两者在自己那一小块都说得通,合起来就不通了。
我当时的情况是:新的数据结构已经建了,旧的读写入口还没换完。结果同一份数据被两个地方按不同的理解写,出了问题时,日志里看不出是哪条路径干的。
避坑的做法是把重构切成一刀一刀能独立收尾的小块,每一块做完就提交、就可用。宁可分十次,也别做成一个跨三周的半成品。
二、坑二:把重构和改需求混在一次改动里
第二个更常见:一边重构一边顺手加功能。
这样做的问题不是不可能,是出问题时你无法归因。如果这次提交只动了结构,跑挂了那就是结构改错了;如果同时加了新功能,你就得先猜是结构的问题还是逻辑的问题,排查成本翻几倍。
我现在的规矩是:重构的提交只做重构,行为不允许变。要加功能,等这次提交验完再说。
三、坑三:没定「什么算改完」就开工
前两个坑的根子都在这里。
开工前必须写下一个可以验收的终点,比如「所有读配置的地方都走同一个入口」「这个包的对外方法从十几个收到几个」。写不出终点,说明这次重构的范围还没想清楚,这时候开工,停手是迟早的事。
一个能被一句话说清楚的终点,比一个漂亮的目录结构重要得多。
四、停手时的止损清单
真到了必须中断的那天,按这四条收拾现场。
1. 把没改完的部分回退到能跑的状态,别留在仓库里。
2. 如果实在回退不了,就在代码里显眼处留一行说明,写清改到哪、还差什么。
3. 把这次没做完的事写进待办,写清「为什么停」,不然下次你只会看到一条没头没尾的条目。
4. 下次开工前,先花时间读一遍自己留下的现场,别直接接着敲。
最后一条以前我总觉得多余,后来发现,重新进入状态花的时间,比那次重构本身还长。这也是为什么我现在宁可不开始,也不轻易开一个会中断的重构。想清楚什么时候该动手,可以对照代码什么时候该重构,看这三个信号里的判断线。
常见问题
Q:重构做了一半停下来会更糟吗?
A:会,但糟的程度取决于你停在哪个位置。停在「新旧写法并存、两边都能跑但语义不一致」时最糟,因为故障难以归因;如果每一小块都收尾干净再停,代价就很小。
Q:怎么判断一次重构切得够不够小?
A:标准是「今天下班前能不能提交一个可用的版本」。能,就够小;不能,就再切一刀。
Q:中断后重新捡起来,有什么办法少花时间?
A:停的时候就留一行现场说明,写清改到哪、下一个动作是什么。别指望未来的自己记得。
相关阅读
本文作者西米,37 岁程序员,一个人加五个 AI 员工在跑一家公司。踩过的坑和真实账本都写在公众号「西米分享」。
完整代码、踩坑清单与最新进展,都在公众号。
📱 关注公众号「西米分享」