有些 bug,修得太干净,反而没人知道它存在过。这大概是程序员最孤独的浪漫。
一、事情的起因:一个"看起来没问题"的模块
公司有个核心订单模块,代码历史可以追溯到 2018 年。五年间,前后端加起来换了 8 拨人,注释里还留着初代架构师的 QQ 号。
这个模块有个特点:看起来一切正常。
- 线上没出过 P0 故障
- 测试用例通过率 100%
- 产品经理三年没提过需求变更
但老程序员都知道, "看起来正常"往往是最危险的信号。
我接手的时候,代码里充斥着这样的"艺术":
JavaScript
scss
// 不要删,删了会崩,原因未知
setTimeout(() => {
if (window.__magic_flag) {
// 2021.3.15 临时修复,待验证
fixSomething();
}
}, 1000);
__magic_flag 是什么?不知道。谁加的?Git blame 显示是一个已注销的账号。fixSomething 干了什么?注释写着"待验证"------已经待了三年了。
二、我决定"考古"
周末我花了两天时间,用 Chrome DevTools 的 Performance 面板 + 手动断点,终于还原了这个模块的"黑历史":
第一层:定时器地狱
那个 setTimeout 是为了解决一个 race condition。2019 年某个版本,后端接口响应变慢,前端为了"兜底",加了个 1 秒延迟。后来接口好了,定时器没删,反而被后续代码依赖上了。
第二层:全局变量瘟疫
__magic_flag 是另一个同事加的,用来标记"是否已经修复过"。但问题是:如果用户快速切换页面,flag 还没重置,修复逻辑就跳过了。
第三层:沉默的灾难
最可怕的是,这个 bug 几乎不会触发。只有在网络抖动 + 用户手速极快 + 特定浏览器版本的叠加态下才会出现。过去五年,线上大概出现了 12 次,每次都被客服用"刷新一下就好了"敷衍过去。
没人报 bug,因为用户刷新后确实好了。测试没发现,因为自动化测试不会"快速切换页面"。
这个模块就像一个埋了五年的地雷,上面还铺了地毯。
三、修复方案:不是打补丁,是拆雷
我没有选择"再加一个 if 判断"这种祖传手艺,而是做了三件事:
1. 用 Promise 链替代定时器
JavaScript
scss
// 之前
setTimeout(() => {
if (window.__magic_flag) fixSomething();
}, 1000);
// 之后
await ensureOrderDataReady();
// 明确的数据就绪信号,不再需要魔法数字
2. 引入状态机管理页面生命周期
TypeScript
ini
type OrderPageState = 'idle' | 'loading' | 'ready' | 'error';
const [pageState, setPageState] = useState<OrderPageState>('idle');
全局变量 __magic_flag 被彻底移除。页面切换时,状态自动重置,不存在"脏状态"残留。
3. 补了 47 个单元测试
覆盖了所有边界条件:网络超时、快速切换、接口返回异常结构、用户断网重连......
用 @testing-library/react 模拟了用户"疯狂点击"的场景,确保状态机不会崩溃。
四、最荒诞的结果
周一我提交 PR,代码审查很顺利。 senior 看了眼 diff,说了句:"就重构了一下?没加新功能?"
我说:"修了几个隐藏 bug。"
他问:"有工单吗?"
我说:"没有,是我周末顺手看的。"
他点点头,合并了。
两周后,更魔幻的事情发生了:
测试组的小妹妹跑来问我:"哥,你那个订单模块的用例能不能分享一下?我们组最近在整理最佳实践,发现你们那个模块特别稳定,三年没出过线上问题,想学习一下。"
我愣了一下,说:"哦......那个啊,确实挺稳定的。"
她认真地点头:"嗯,我们领导说这种'原生稳定'的模块最有参考价值,不像有些模块,天天修 bug。"
我张了张嘴,最终没告诉她真相。
五、程序员的"修 bug 悖论"
这件事让我想明白了一个道理:
在软件工程里,bug 的可见度和它的危险程度,往往是成反比的。
- 那些天天报错的模块,大家抢着修,反而很健康。
- 那些"从来没问题"的模块,可能藏着最可怕的债务。
而当你把后者真正修好,没有人会感谢你------因为他们根本不知道原来有问题。
测试组以为这个模块"本来就没问题"。 领导以为我只是"优化了一下代码结构"。 甚至三个月后的我自己,如果不看 Git 历史,也会以为这模块天生就这么干净。
六、唯一的证据
唯一知道这个秘密的,是 Git 里那条 commit message:
plain
diff
refactor(order): 移除魔法定时器与全局状态标记
- 用 Promise 替代 setTimeout 轮询
- 引入 OrderPageState 状态机
- 补充边界条件测试 47 例
- 移除 __magic_flag(2019 年遗留)
BREAKING CHANGE: 无,行为保持一致
以及我本地那份 3000 字的"考古笔记",记录了 __magic_flag 的前世今生。
七、写在最后
有人说,程序员最好的作品是"没人注意到的代码"------它稳定运行,不报错,不卡顿,不需要解释。
但我想说,程序员最孤独的作品,是"没人知道它曾经坏过"的修复。
你花了两个周末,拆掉了一颗五年的地雷,铺上了真正坚固的地基。然后看着测试组把它当成"原生优秀案例"写进最佳实践文档。
这算不算一种成功?
算吧。只是有点寂寞。
如果你也拆过这样的雷,欢迎在评论区留下你的故事。至少在这里,有人懂。