凌晨两点,一个本地跑得好好的项目在服务器上编译失败,报错指向第 217 行的类型不匹配。我盯着那行代码看了四十分钟,它无辜得像刚洗过的白衬衫。
四个小时的完整弯路
- 第 1 小时:坚信是类型系统的问题,重构了三层调用关系;
- 第 2 小时:开始怀疑编译器(是的,凌晨的人敢怀疑编译器);
- 第 3 小时:升级了编译器版本,问题依旧,但产生了新的怀疑对象:操作系统;
- 第 4 小时:破罐破摔,从头跑了一遍完整日志,在第 38 行看到了真正的报错——我夜里只盯着屏幕最后 20 行看。
真相只有一行
日志第 38 行写着:warning: configuration file not found, using defaults。服务器上根本没有那份配置文件,程序一路用默认值跑,默认值里一个路径写死了本地目录,才在 217 行炸出那个与我无缘的类型错误。真正的病根在 179 行之前,而我从第 217 行开始考古。
调试最贵的成本从来不是修复那一行,是你带着错误假设跑过的四个小时。
从此生效的三条军规
- 从第一条日志读起:报错现场往往在尸检报告的最后一页,但病因从来不在那里;
- 凌晨两点不做架构决策:改类型、换框架、升级编译器都属于这一类,睡醒再做,问题通常在枕头上就解了;
- 设一个 45 分钟闹钟:同一问题钻研超过 45 分钟还没头绪,强制起身写"问题陈述"——用三句话向外人描述它。多数时候,写到第二句就发现了自己的假设漏洞。
那次事故的修复时间:删除一行注释、上传一个配置文件,用时 40 秒。四小时与 40 秒的差值,就是假设未经检验的代价。现在它是我带新人时必讲的故事,讲完都要补一句:日志,从第一行开始读。