作为一名程序员,你一定遇到过这种情况:代码库里有一坨”祖传代码”,你看它不顺眼很久了,也清楚知道它的问题,甚至列好了重构计划——但就是迟迟动不了手。一周拖一周,延期变成了习惯,而那堆代码依然在那里,像一根刺一样时不时扎你一下。
这不全是你的问题。这背后有深刻的认知心理学和经济学原因。今天我们就来聊聊,为什么重构总是被无限期拖延,以及如何真正打破这个循环。
一、沉默的成本:沉没成本谬误
经济学里有个概念叫沉没成本谬误(Sunk Cost Fallacy):人们在决定是否做某件事时,不仅会考虑它未来的收益,还会不自觉地受已经投入的资源所影响。
反映在代码上是什么样子?
这段代码我花了三周才写出来,现在要重写?那我这三个月的时间岂不是白费了?
但真相是:你已经投入的那部分时间和精力,是沉没的,无论你接下来做什么重构或者不重构,那部分成本都无法回收。理性的决策只应该考虑:从现在开始,做还是不做,哪个对未来更好?
而当你继续维护一团乱代码,每次修改都要多花两小时,你其实是在为”保护过去的投入”付出更大的代价。
二、即时满足 vs 延迟奖励:大脑的天生偏见
人类大脑天生偏好即时奖励。一个新功能的开发,几天就能看到效果、收到反馈、得到认可;而重构的效果是潜在的、长期的,甚至没有人会注意到”这次修改因为代码更清晰,提前一小时完成了”。
因此,即便你知道重构长期有益,大脑依然会把你推向”先做功能”的方向——因为功能可以被展示、被表扬、被计入KPI,而干净的代码不会。
这在团队中也很明显:重构的成果难以量化,它的价值只能在未来的某次修改中才能体现。这也是为什么重构总是要给新功能开发让路。
三、确定性偏好:已知的风险大于未知的机会
行为经济学还发现,人对损失的厌恶程度大约是对同等收益感受的两倍。我们宁愿维持一个有缺陷但”能用”的状态,也不愿意冒险重构后引入新的问题。
这代码虽然烂,但跑了好几年没出过大事;万一重构改出问题,谁负责?
这个顾虑是合理的,但往往被夸大了。很多重构失败,不是因为技术难度高,而是因为缺少测试保障、缺少分阶段验证的策略。一旦有了完善的测试覆盖和渐进式的重构方法,风险是可控的。
四、破解之道:让重构从不可能任务变成日常习惯
1. 童子军规则
Bob大叔提出的童子军规则很简单:离开时,让代码比来时更干净。不要试图一次性重构整个模块,而是每次接触某段代码时,只改善一点点。变量命名不好的改一改,函数太长的拆一下,嵌套太深的提前返回。
这个方法的好处是:不需要专门安排时间,不需要大张旗鼓的”重构项目”,只要形成习惯,日积月累,代码质量会显著提升。
2. 将重构嵌入迭代周期
不要把重构当作独立于功能开发之外的工作。正确的做法是:每个任务卡(Ticket),在完成功能需求的同时,顺便把相关的代码质量问题一起处理。把重构当作开发的标准步骤,而非额外负担。
3. 建立安全网:自动化测试
重构最大的恐惧来源于不确定性,而自动化测试是消除不确定性的最好工具。在开始重构前,先补测试;有了测试覆盖,重构的信心会大幅提升。
4. 设定最小可重构单元
不要想着”我要重构整个模块”。先从最小的有意义单元开始:比如一个函数、一张表结构、一个接口定义。完成一个,再下一个。每一次小的成功,都会积累信心,推动下一次行动。
5. 量化重构收益
试着记录下来:因为代码质量问题,每次修改平均多花了多少时间?有了数据,你就可以向团队证明重构的价值,把重构从”可选项”变成”必选项”。
五、写在最后
重构延期,本质上是一个认知偏见和激励机制错配共同导致的问题,而不是意志力或能力的缺陷。认识到这一点,本身就是一种解脱。
下一次你盯着那段乱代码犹豫时,不妨对自己说:这只是一次决策偏见,不是我的错。但打破它,是我的责任——不为别人,就为未来那个需要修改这段代码的自己。
代码是写给人看的,顺带让机器运行。善待未来的自己,从今天开始,一次重构一个函数。
你有哪些关于重构的真实经历或困惑?欢迎在评论区分享。