重读《重构》最大的收获不是那些具体手法,而是它对"什么时候该动手"这个问题的回答。以前我总觉得重构需要一个专门的排期,书里给出的答案恰恰相反。
坏味道不等于问题
书里列了二十多种坏味道:过长函数、重复代码、过大的类、发散式变化……刚开始我把它当成一份"待办清单",看到就想改。
后来才想明白,坏味道只是提示,不是判决。一个函数有两百行确实难读,但如果它半年都不会被改动一次,重构它的收益就接近于零——你只是把风险从一个地方挪到另一个地方。真正该动的,是那些你马上要改、却因为结构糟糕而改不动的地方。
判断标准不是"这段代码丑不丑",而是"我接下来要改它吗"。
重构不需要专门排期
这是全书最反直觉、也最实用的一点。重构应该夹在"添加新功能"和"修复缺陷"之间,作为达成目的的手段,而不是一个独立任务。
理由很实在:专门申请的重构排期,往往申请不到,或者申请到了也做不完。而"我要加这个功能,先把这块结构理一下才好加",这类改动小、目标明确、风险可控,反而容易推进。
测试的优先级高于重构
书里反复强调:没有测试的重构,不叫重构,叫"瞎改"。因为重构的定义就是在不改变外部行为的前提下调整内部结构,而没有测试,你根本无法证明行为没变。
所以优先级是这样的:
- 先补上这块代码的测试,哪怕只是最粗糙的冒烟测试;
- 跑一遍,确认绿的;
- 做小步重构,每改完一步就跑测试;
- 测试红了,立刻回到上一步。
小步是关键。一次只做一件事,改完立刻验证。不要攒着一堆改动一起提交——出问题的时候,你会连是哪一步引入的都查不出来。
什么时候才该重写
这是最容易被误用的判断。重写的诱惑在于"从头来过一定更干净",但经验告诉我们,重写项目通常死在两个地方:一是低估了旧代码里那些看起来莫名其妙、实则为了解决特定问题的逻辑;二是重写期间新需求还在涌入,最后两套系统并行,哪个都没做好。
书里的立场很克制:能重构就别重写。只有当以下条件同时满足时,重写才划算:
- 这块代码你已经完全理解,知道它为什么要这么写;
- 它的边界清晰,可以隔离出来单独替换;
- 你有足够的测试能验证重写后行为一致;
- 重构的代价已经高于重写的代价。
四个条件里,第一个最难满足,也最容易被跳过。
技术债该怎么还
把技术债当成"欠债"来理解就清楚了:不是不能欠,而是要清楚利率,并且有计划地还。有些债利率很低(那块代码几乎不改),欠着无所谓;有些债利率极高(每天都要碰,每次都痛),必须优先偿还。
我的做法是:每次改到某块代码,就顺手把它清理得比之前好一点。不用多,好一点就够。时间一长,高频改动的代码自然会越来越干净,而那些从没被碰过的地方,本来也不值得投入。
小结
重构不是一次性的大扫除,而是一种持续保持代码可修改性的习惯。判断该不该动,看的是"我接下来要不要改它",而不是"它够不够优雅"。至于重写——把它当成最后手段,而不是第一反应。
— 全文完 —