重构做一半停手,代价比想象大

去年有一版代码我改到一半,被一个更急的活插进来,就搁下了。三周后回去看,那段代码一半是新写法、一半是老写法,我自己都分不清哪个是哪个。那次之后我才搞明白,重构做了一半停下来会更糟吗——答案不是「会不会更糟」,是「你到底停在哪一步」。

最贵的一课就一句话:重构的真正代价不在改的时候,在停的时候。

一、坑一:停在「两套写法并存」的中间态

代码重构最危险的状态不是旧代码,是新旧各占一半。

老代码虽然难看,但它自洽——函数怎么调、数据怎么流,是一整套。你改了一半之后,一部分走新路径、一部分走老路径,两者在自己那一小块都说得通,合起来就不通了。

我当时的情况是:新的数据结构已经建了,旧的读写入口还没换完。结果同一份数据被两个地方按不同的理解写,出了问题时,日志里看不出是哪条路径干的。

避坑的做法是把重构切成一刀一刀能独立收尾的小块,每一块做完就提交、就可用。宁可分十次,也别做成一个跨三周的半成品。

二、坑二:把重构和改需求混在一次改动里

第二个更常见:一边重构一边顺手加功能。

这样做的问题不是不可能,是出问题时你无法归因。如果这次提交只动了结构,跑挂了那就是结构改错了;如果同时加了新功能,你就得先猜是结构的问题还是逻辑的问题,排查成本翻几倍。

我现在的规矩是:重构的提交只做重构,行为不允许变。要加功能,等这次提交验完再说。

三、坑三:没定「什么算改完」就开工

前两个坑的根子都在这里。

开工前必须写下一个可以验收的终点,比如「所有读配置的地方都走同一个入口」「这个包的对外方法从十几个收到几个」。写不出终点,说明这次重构的范围还没想清楚,这时候开工,停手是迟早的事。

一个能被一句话说清楚的终点,比一个漂亮的目录结构重要得多。

四、停手时的止损清单

真到了必须中断的那天,按这四条收拾现场。

1. 把没改完的部分回退到能跑的状态,别留在仓库里。

2. 如果实在回退不了,就在代码里显眼处留一行说明,写清改到哪、还差什么。

3. 把这次没做完的事写进待办,写清「为什么停」,不然下次你只会看到一条没头没尾的条目。

4. 下次开工前,先花时间读一遍自己留下的现场,别直接接着敲。

最后一条以前我总觉得多余,后来发现,重新进入状态花的时间,比那次重构本身还长。这也是为什么我现在宁可不开始,也不轻易开一个会中断的重构。想清楚什么时候该动手,可以对照代码什么时候该重构,看这三个信号里的判断线。

常见问题

Q:重构做了一半停下来会更糟吗?

A:会,但糟的程度取决于你停在哪个位置。停在「新旧写法并存、两边都能跑但语义不一致」时最糟,因为故障难以归因;如果每一小块都收尾干净再停,代价就很小。

Q:怎么判断一次重构切得够不够小?

A:标准是「今天下班前能不能提交一个可用的版本」。能,就够小;不能,就再切一刀。

Q:中断后重新捡起来,有什么办法少花时间?

A:停的时候就留一行现场说明,写清改到哪、下一个动作是什么。别指望未来的自己记得。

相关阅读


本文作者西米,37 岁程序员,一个人加五个 AI 员工在跑一家公司。踩过的坑和真实账本都写在公众号「西米分享」。

完整代码、踩坑清单与最新进展,都在公众号。

📱 关注公众号「西米分享」