面对Bug程序员能做点什么

Bug之殇
所谓bug,就是程序当中的出现的缺陷或者错误,他们会导致程序出现一些不合预期的结果,甚至会导致崩溃。

1947年9月9日下午3点45分,格蕾丝·霍珀在她的记录本上记下了史上第一个计算机Bug——在Harvard Mark II计算机里找到的一只飞蛾,她把飞蛾贴在日记本上,并写道”First actual case of bug being found”。
面对Bug程序员能做点什么
历史上有一些后果非常严重的Bug。

宰赫兰导弹事件

1991 年 2 月第一次海湾战争期间,部署在沙特宰赫兰的美国爱国者导弹系统未能成功追踪和拦截来袭的伊拉克飞毛腿导弹。结果飞毛腿导弹击中美国军营。当场炸死28个美国士兵,炸伤100多人,造成美军海湾战争中唯一一次伤亡超过百人的损失。

时间计算不精确以及计算机算术错误导致了系统故障。从技术角度来讲,这是一个小的截断误差。当时,负责防卫该基地的爱国者反导弹系统已经连续工作了100个小时,每工作一个小时,系统内的时钟会有一个微小的毫秒级延迟,这就是这个失效悲剧的根源。爱国者反导弹系统的时钟寄存器设计为24位,因而时间的精度也只限于24位的精度。在长时间的工作后,这个微小的精度误差被渐渐放大。在工作了100小时后,系统时间的延迟是三分之一秒。雷达在空中发现了导弹,但是由于时钟误差没有能够准确地跟踪它,因此基地的反导弹并没有发射。

英特尔奔腾处理器

1994 年,英特尔的奔腾微处理器芯片的浮点计算单元出现了一个 Bug。对于精确计算,处理器将返回不正确的十进制值。当时有大概 500 万个缺陷芯片在流通,英特尔最终决定为所有投诉的人更换芯片。这之后,英特尔把他们的故障处理器做成了钥匙链。预计损失为4.75 亿美元

在奔腾浮点单元的分频器中有一个有缺陷的除法表,在约一千个条目中丢失了五条纪录。然而,这个错误在 90 亿随机浮点小数的除法中仅可能出现一次。例如,将 4195835.0 除以 3145727.0 得出 1.333739068902037589,而不是 1.333820449136241002,有 0.006% 的误差。

阿丽亚娜5型运载火箭

1996年6月4日,阿丽亚娜5型运载火箭的首次发射点火后,火箭开始偏离路线,最终被逼引爆自毁,整个过程只有短短30秒。

阿丽亚娜5型运载火箭基于前一代4型火箭开发。在4型火箭系统中,对一个水平速率的测量值使用了16位的变量及内存,因为在4型火箭系统中反复验证过,这一值不会超过16位的变量,而5型火箭的开发人员简单复制了这部分程序,而没有对新火箭进行数值的验证,结果发生了致命的数值溢出。发射后这个64位带小数点的变量被转换成16位不带小数点的变量,引发了一系列的错误,从而影响了火箭上所有的计算机和硬件,瘫痪了整个系统,因而不得不选择自毁,因此损失了3.7 亿美元。

Bug的分类与应对

美国计算机科学家、图灵奖获得者詹姆斯·尼古拉·格雷(Jim Gray),在他的著名的论文中首次提出了程序bug的类型,根据bug的出现情(如能否复现)况分成如玻尔bug(Bohrbug)、 海森堡bug(Heisenbugs)等

而然我还是希望能够从bug成因的角度进行分类,这样才能够好的避免bug,以下是大胡子的分类法以及应对方案:

算法Bug

成因:由于程序员对算法实现错误而产生的bug,如奔腾处理器的长除法问题。

应对方案:单元测试

算法Bug相对独立,可以通过对算法模块本身的充分测试来发现问题。这些测试通常都是比较容易自动化的,即通过程序定制输入,判断是否出能得到预期 的输出,来保证正确性。

回归Bug

成因:由于产品功能调整,版本更新,出现了原有的代码没有考虑到的情况,导致出现问题,阿丽亚娜5型运载火箭就属于这个问题。

应对方案: 回归测试

通过重新运行原有功能的测试case,保证以前的功能符合预期。

场景bug

成因:并非单个功能点有问题,而是由于使用的场景和用户的预期不符,导致输入错误,或者使用流程出现了没有考虑到的情况。比如支付宝的找回密码问题。这类问题通常并非全是程序员的原因,产品经理也对此负有责任。

应对方案:测试服务器/测试环境

复杂的bug很难通过简单的测试发现,需要一定的用户使用量,通常公司会采用一个测试环境邀请一批用户进行试用,从而尽可能的发现bug。比如著名的游戏公司暴雪,在更新他们所有的游戏版本之前,会先更新到测试服务器(即PTR服务器),这个服务器是公开的,通过这样的方式来收集用户的反馈。这已经是一个非常成熟的过程。

累计bug

成因:冰冻三尺非一日之寒,此类bug通常由于微小的错误累计而成,短时间内不易察觉,然而程序长时间运行后,可能会引起严重的后果,如:宰赫兰导弹事件中的bug,或者内存泄露,性能问题等

应对方案:测试服务器/压力测试

测试服务器是一个不错的方案,你可以在这里长期运行你的程序,从而发现问题。压力测试可以更有针对性的判断你的程序在一定的工作量情况下是否会产生问题。

以上,便是我对于程序bug的一些思考,希望对大家有所帮助。

上一篇:BigDecimal数据加法返回值接收


下一篇:os层删除与数据库层drop的区别于对策。