重读《重构》最大的收获不是那些具体手法,而是它对"什么时候该动手"这个问题的回答。以前我总觉得重构需要一个专门的排期,书里给出的答案恰恰相反。

坏味道不等于问题

书里列了二十多种坏味道:过长函数、重复代码、过大的类、发散式变化……刚开始我把它当成一份"待办清单",看到就想改。

后来才想明白,坏味道只是提示,不是判决。一个函数有两百行确实难读,但如果它半年都不会被改动一次,重构它的收益就接近于零——你只是把风险从一个地方挪到另一个地方。真正该动的,是那些你马上要改、却因为结构糟糕而改不动的地方。

判断标准不是"这段代码丑不丑",而是"我接下来要改它吗"。

重构不需要专门排期

这是全书最反直觉、也最实用的一点。重构应该夹在"添加新功能"和"修复缺陷"之间,作为达成目的的手段,而不是一个独立任务。

理由很实在:专门申请的重构排期,往往申请不到,或者申请到了也做不完。而"我要加这个功能,先把这块结构理一下才好加",这类改动小、目标明确、风险可控,反而容易推进。

测试的优先级高于重构

书里反复强调:没有测试的重构,不叫重构,叫"瞎改"。因为重构的定义就是在不改变外部行为的前提下调整内部结构,而没有测试,你根本无法证明行为没变。

所以优先级是这样的:

  1. 先补上这块代码的测试,哪怕只是最粗糙的冒烟测试;
  2. 跑一遍,确认绿的;
  3. 做小步重构,每改完一步就跑测试;
  4. 测试红了,立刻回到上一步。

小步是关键。一次只做一件事,改完立刻验证。不要攒着一堆改动一起提交——出问题的时候,你会连是哪一步引入的都查不出来。

什么时候才该重写

这是最容易被误用的判断。重写的诱惑在于"从头来过一定更干净",但经验告诉我们,重写项目通常死在两个地方:一是低估了旧代码里那些看起来莫名其妙、实则为了解决特定问题的逻辑;二是重写期间新需求还在涌入,最后两套系统并行,哪个都没做好。

书里的立场很克制:能重构就别重写。只有当以下条件同时满足时,重写才划算:

  • 这块代码你已经完全理解,知道它为什么要这么写;
  • 它的边界清晰,可以隔离出来单独替换;
  • 你有足够的测试能验证重写后行为一致;
  • 重构的代价已经高于重写的代价。

四个条件里,第一个最难满足,也最容易被跳过。

技术债该怎么还

把技术债当成"欠债"来理解就清楚了:不是不能欠,而是要清楚利率,并且有计划地还。有些债利率很低(那块代码几乎不改),欠着无所谓;有些债利率极高(每天都要碰,每次都痛),必须优先偿还。

我的做法是:每次改到某块代码,就顺手把它清理得比之前好一点。不用多,好一点就够。时间一长,高频改动的代码自然会越来越干净,而那些从没被碰过的地方,本来也不值得投入。

小结

重构不是一次性的大扫除,而是一种持续保持代码可修改性的习惯。判断该不该动,看的是"我接下来要不要改它",而不是"它够不够优雅"。至于重写——把它当成最后手段,而不是第一反应。

— 全文完 —