在软件工程的世界里,错误(bugs)就像夜晚的幽灵,它们会在最不经意的时候出现,让彻夜难眠,甚至从沉睡中惊醒。这些错误构成了伟大故事的基础,因为就像许多伟大的故事一样,它们包含了所有要素:
开端:“天哪!这里有个错误。”
上升情节:“让深入挖掘,看看这个问题有多普遍,以及如何缓解它。”
高潮:“找到了!”的那一刻,缩小了错误确切原因的范围。
下降情节:“实施修复,验证它解决了问题。”
结局:“将修复合并到源代码控制中,知道这个错误将永远消失!”
在一个好的错误中,可以找到极大的满足感。探索的过程,追逐的兴奋,最后抓住那个错误,用极端的偏见结束它。
不幸的是,并非所有的故事都有快乐的结局;有时,错误逃脱了。
开端:
这个故事的开始就像大多数错误故事一样——一个遗留的软件系统。这里没有什么特别的,一个老旧的、拼凑的前端,一个企业级的数据库等等。如果看过一个,就看过它们所有。
无论如何,在即将到来的一个重大版本发布之前——收到了一个同事的消息,让看看某件事。数据库中的一条记录被一些非常奇怪的编码模式破坏了。这些编码模式似乎没有任何规律或原因,它就是混乱和不一致的,与应用程序的其他部分完全不同:
记录A:看,一切都很好,很闪亮!
记录B:看,一切都很好,&闪亮!
记录C:看,一切都很好,很闪亮!
所以,看到这一点——说了任何好的开发者都会说的话:“哦,这应该是一个相当简单的修复。”。
上升情节:
软件工程充满了错误。
有无数大大小小的系统都充满了这些东西。作为一个工程师,非常清楚这一点,因为也贡献了不少。做了大约十年的软件工程师,一直认为自己是彻底的,特别是在追踪错误的时候:研究,深入挖掘,最后:修复。
像任何错误一样——修复它的第一步之一就是能够重现它。和QA团队谈过,他们最初无法重现它,但提到他们会进一步调查。几个小时过去了,收到了另一条消息,大意是:
QA人员:Rion,刚刚启动了一个全新的环境,可以重现这个问题!
在这一点上,很兴奋。已经和这个问题斗争了一整天,即将跳进修复错误的兔子洞,来解决这个问题。登录到新环境,确实,QA是对的!可以重现它!应该在几分钟内就能解决这个问题,一天得救了!
或者以为是这样。
在能够重现问题后的大约两小时,它停止出现了。
字面上是在向同事展示问题的过程中,几分钟后,它就完全消失了。这怎么可能呢?环境里什么都没有改变,没有机器或Web服务器重启,没有配置更改,什么都没有。错误,在几个小时后,似乎自己解决了。
跳到最后一页:
通常作为故事上升情节的一部分,事情会逐渐建立,直到达到一个点。在故事中,应该已经找出了根本原因。错误显然在短时间内是可重现的,但不足以确定确切的原因(这台机器有很多移动部件)。所以,开始冒险寻找一条路径,爬上那个调试的山。把所有的技巧都拿出来了,包括:
检查IIS日志
- 在多个环境中,检查了生产环境中出现问题的IIS日志,在短期内可重现的QA环境,本地环境。
检查事件查看器日志
- 也许有一种异常导致Web服务器重启,并神奇地解决了问题。肯定会有东西在那里。
分析环境
- 在问题可重现的时候,利用了SQL Server Profiler,并记录了对数据库执行的确切调用。
反编译生产代码
- 用一个绝望的尝试,试图从生产环境中反编译代码,以确保没有代码变化是不同的,也没有超出预期的调用被执行。
什么都没有帮助。尝试的每一个新途径都只会让更加困惑,让想知道到底是什么导致了这个问题。把所有的碎片放在一起,可以基本上描述这个问题如下:
怎么可能通过两组调用,都通过相同的端点,传递相同的数据,执行相同的查询对相同的
确切的
存储过程,导致不同的数据(一个是损坏的,另一个不是)。
多年来第一次,被一个错误打败了。开始抓住救命稻草,寻找竞态条件,可能影响代码的外部力量,网络节流问题,什么都没有。
错误赢了:
许多日日夜夜过去了。这个错误让在夜里醒来,梦想着可能的原因,然后跑到电脑前尝试它们,最终意识到它们不起作用。像每一个好的工程师一样,在遇到这个问题后几分钟就想到了一个解决方法,但决心不走到那里。
在当地看到了这个问题,即使是短暂的,在几个QA环境中(又是短暂的),在几个生产环境中。尝试了能想到的一切,咨询了无数的同行来思考原因,但所有的结果都是在整个团队中传播困惑。
这个看似微不足道的错误逃避了所能想到的每一种捕捉/解决形式。它留下的只是困惑,不仅对,而且对每一个试图展示问题的人。最终,就像医生一样,不得不放弃。
在花了超过一周的时间,白天和黑夜,追求这个错误之后:它赢了。
不会有高潮,不会有快乐的结局,不会有那种温暖的、模糊的成就感;只会有几行hacky代码来修复它。
感觉就像朋友查理·布朗,这个错误在有机会踢球之前就把足球夺走了。
它发生了:
写这个的原因,或者它值得写的原因,与错误本身无关。它与有关,也许甚至与有关。一直认为自己很擅长解决问题,而且很彻底。会深入挖掘,继续挖掘,探索,直到能破解问题,直到在这种情况下:不能。
作为一个工程师,通常是关于解决问题,但更重要的是,它是关于实际的。
可以轻易地再花几天(和夜晚)试图解决这个问题,找出它为什么会发生,但老实说,修复它的时间不超过5分钟。这是关于能够承认失败。就像
没有什么不对的承认“不知道”