去年Q3的某个深夜,我在一个老项目里追一个看似简单的bug。光标在IDE里上下翻飞,咖啡凉了第三杯,时间从22:47走到凌晨2:15。最后发现问题出在一行2019年写的代码——变量名叫tmp,注释是空的,同样的逻辑在三个文件里各有一份,只是顺序调换了下。
写这行代码的人,就是我自己。
那时候项目deadline火烧眉毛,产品经理在飞书群里@我第七次,测试环境已经崩了两轮。我告诉自己:先跑起来,后面再重构。这个"后面",一等就是三年。
技术债的复利,比房贷还狠
那次debug的经历让我算了笔账。赶工时省下的20分钟,三年后变成了4小时15分钟。这还没算中间两次"小修小补"浪费的1.5小时——当时我以为自己"快速修复"了,其实只是给雷换了根引线。
更隐蔽的成本是认知负荷。面对一团自己写的、却完全陌生的代码,那种挫败感很难量化。神经科学里有个概念叫"认知切换成本"(cognitive switching cost),每次在不同模块间跳转,大脑需要重新加载上下文。我的那坨代码,把切换成本拉到了极限:变量d在A文件里是日期,在B文件里是距离,在C文件里居然是个布尔标志位。
「我们总以为自己在写代码给机器执行,」一位在Google干了12年的工程师朋友跟我说,「实际上你是在写给六个月后的自己——而那时的你,基本是个陌生人。」
这话刺耳,但我现在每天写注释的时候都会想起。
那些"以后再说"的陷阱
我复盘了当年埋雷的具体操作,堪称反面教材全集:
复制粘贴三处同样的校验逻辑,而不是抽成一个函数。理由很充分:这个逻辑"暂时"只在两个地方用,抽函数"过度设计"。三个月后第三个地方出现了,我复制粘贴时漏改了一个条件——这就是那个深夜bug的根源。
变量命名走极简风。a、arr、data、item轮番上阵。当时的想法是:代码这么短,看一眼就懂。事实是,三年后我连"这么短"是多短都忘了,更别提"懂"的是什么业务场景。
零注释。复杂的正则表达式?自解释。嵌套三层的条件判断?逻辑清晰。直到某天业务方说"这个规则要改",我才发现自己读不懂自己的"清晰逻辑"。
最讽刺的是,我当时并非不懂这些道理。每本技术书、每次code review,这些原则都被反复强调。但 deadline 的压力会扭曲判断力,把"可维护性"归类为"理想主义者的奢侈品"。
我现在用的笨办法
那件事之后,我给自己定了几条土规矩,不 fancy,但管用:
命名多打几个字。从tmp改成pendingOrderTimeoutThreshold,多按了20下键盘,但省下的脑力远超于此。有个经验法则:变量名长度应该跟作用域大小成正比。全局变量就该长得像个句子,局部循环变量叫i也无妨。
强制注释"为什么"而非"是什么"。代码本身说清了做什么,注释要解释的是:这个魔法数字从哪来的?这个分支排除了什么边界情况?下次动这里要检查什么?
复制粘贴超两次,必须抽函数。不是"考虑抽",是"必须"。这个硬门槛帮我拦截了至少80%的重复逻辑扩散。
每次提交前问自己:如果明天我车祸失忆了,同事能接手吗?这个问题有点极端,但能有效对抗"我现在记得很清楚"的幻觉。
一个可能让你不舒服的事实
我后来跟团队里的年轻工程师聊过,发现很多人把"代码质量"和"过度工程"混为一谈。他们觉得追求可维护性就是 premature optimization,就是"为了优雅而优雅"。
这种理解有个盲区:可维护性不是镀金,是保险。你不会因为"可能不出车祸"就不买车险,也不该因为"项目可能活不过三个月"就拒绝写注释。那个项目后来跑了五年,我2019年的"临时方案"成了核心路径上最稳定的组成部分——稳定地制造痛苦。
「技术债和财务债的区别在于,」那位Google朋友补了一刀,「债主不会上门催你,但利息会自动复利,直到某个凌晨两点,你连本带利一起还。」
我现在写代码的速度确实比三年前慢了。一个功能从"2小时写完"变成"2.5小时写完,其中30分钟花在命名和注释上"。但过去半年,我在旧代码里的debug时间,从平均每月6小时降到了40分钟。
这笔账,越算越觉得那30分钟花得值。
你最近有翻到自己写的"黑历史"吗?那次花了多久才看明白自己在想什么?
热门跟贴