一只老鼠在仓库里活了十八年,猫换了七任,夹子换了十种,它都没死。最后弄死它的,不是来了一只天赋异禀的猫,而是墙角突然铺满脚印。我一直觉得,老bug(程序错误)的克星不是天才,是病例分布。所谓core dump(程序崩溃后留下的内存尸体),不是遗书,是疫区地图。
人们爱把修老bug想成武侠:闭关三天,翻完祖传代码,一剑封喉。这个想象很迷人,因为它给个人英雄主义发工资。可十八年的bug,往往不是一条深不可测的龙,而是一阵长期被误诊的咳嗽。修这种东西,靠的不是侦探学,靠的是流行病学:看病例怎么扎堆,怎么迁徙,怎么在某些角落反复出现。
一个错误能活十八年,不是因为它太聪明,而是因为受害者太分散。
凌晨两点十七分,华南一座小城的便利店,夜班店员扫完一箱进口啤酒,准备打印退货小票,收银程序突然黑屏。值班工程师爬起来重启,机器又活了,日志干干净净,像一个装傻的嫌疑人。第二天,大家把锅甩给门店网络。因为崩得少,少到像一粒灰,没人肯为一粒灰停下整条流水线。
周一早上八点零五,县医院挂号机前排着十几个人。一个老人替孙子挂号,输完姓名,屏幕卡死。护士骂机器旧,外包人员骂用户乱按,管理员骂系统“历史包袱重”。这种抱怨最省力:它谁都像在说话,其实谁也没说。机器重启后又能跑,于是故障像一滩水,被拖把一推,表面干了,地板芯子还是湿的。
下午五点四十,外贸公司会计导出月报,客户名单里有一串很长的公司名,后面还跟着全角括号,程序啪地一下退掉。她先以为自己点错了,第二次、第三次还是退。客服把工单记成“偶发闪退”。这四个字很体面,体面得像给尸体盖白布,礼貌而无用。
这三起事,在各自现场都像小概率倒霉。真正的转折,不发生在某位资深工程师突然顿悟,而发生在有人把core dump一份份摊开:崩溃前的输入长度、系统版本、打印模板、机器型号、调用路径,不是看一份,而是看一百份。于是脚印出来了:三批受害者,都死在同一个窄门口。
那段十八年前留下的旧代码,像一个自作聪明的小抽屉,只给了255个格子,却以为天下的字都一样宽。平时英文短名、短票据、短字段,挤一挤也能过;一碰上中文、全角符号、长模板,抽屉就夹手,程序就猝死。老bug不是藏在代码深处,它是藏在使用人群的边角里。
一个core dump只告诉你死法,十个core dump才告诉你谁在连环作案。
这就是为什么我对“某大神终于拿下十八年顽疾”这种说法,向来只肯半信。大神当然重要,但多数时候,他真正做的不是凭天眼看穿宇宙,而是终于拿到了像样的病例表。没有病例分布,再聪明的人也只能对着祖传代码做周易;有了病例分布,一个普通工程师都能顺着脚印摸到鼠洞。
没有病例分布,再聪明的人也只能对着祖传代码做周易。
很多团队偏偏最不肯做这件最土的事:统一收集core dump,给每次崩溃补上时间、设备、输入特征,让一线抱怨进系统,而不是进空气。公司爱给救火英雄发奖,因为英雄适合写年终总结;病例分布不光彩,像扫街、填表、钉地图,既不浪漫,也不适合拍海报。但老bug偏偏怕这个。它不怕聪明,它怕受害者不再零散;不怕推理,它怕零碎惨叫被整理成同一种语言。
老bug不怕聪明,它怕受害者不再零散。
说到底,这不只是修程序的方法,也是理解复杂问题的方法。我们太迷信天才,太轻视分布;太爱听一锤定音,太懒得看那些琐碎、带泥、没戏剧性的样本。可真正顽固的东西,常常不是靠灵光一现被拿下的。下水道总在同一条街返味,学校里总有某类孩子在同一节课消失,系统里总有某类请求在同一张模板前猝死,本质上都是一回事:先别急着崇拜侦探,先把病例图画出来。
所以我的判断很硬:core dump是尸检,病例分布是追捕。前者告诉你人怎么死,后者告诉你凶手住哪。一个错误能活十八年,不是因为它像神话里的怪物,而是因为它学会了在人群里稀释自己;一个错误终于被修掉,也不是因为天才天降,而是因为那些零星死法,终于被排成了队。
别人聊 AI,我们测 AI——每个结论都能下载原始数据自己复算。 🔗 官网 👉 https://crawdpad.com