有没有一种情况:程序有bug,代码却是正确的?
作者:网络转载 发布时间:[ 2013/1/14 10:06:53 ] 推荐标签:
在查看了汇编代码后,我确定是编译器导致了错误的结果,因此向Microsoft发出了一个bug报告——也是我提交的第一个编译器bug报告。很快我得到了回应,回想起来还真是让人惊讶:Microsoft的编译器在世界范围内是如此地流行,我的bug报告竟然得到了回应,而且非常之快!
或许你能猜到——这不是一个bug,虽然我看了很久的代码,但是却还是忽略了一个小错误。我很疲惫——连续数周每天12小时以上的工作——所以没发现这是不可能工作的代码。一个单位不能既非“采伐者”又非“非采伐者”。Microsoft的测试人员礼貌地回复了我的失误,但那时我却感到被羞辱了,但幸好bug可以解决了。
顺便说一下,压缩时间是一个失败的开发模式,我在博客上很多篇文章中都提到过,这里也一样:疲惫的开发者很容易犯一些低级错误。合理地安排工作时间才能得到更高的开发效率,所以,回家休息去吧,然后明天再以饱满的精神面来编写代码!当我和两个朋友开始创办ArenaNet时,“没有危机”正是我们开发的哲学基础,原因之一在于我们没有在办公室置办足球桌和街机。工作-回家休息-再工作!
这回bug真的出在Microsoft身上了!
几年后,在开发Guild War时,我们发现了一个灾难性的错误会导致游戏服务器在启动时崩溃。不幸的是,我们编程团队日常使用的“dev”(development)分支没有任何问题,测试团队后验证用的“stage”(“staging”)分支也没有问题。出现问题的地方在于“live”分支,也是玩家使用的分支。我们把这个版本“推送”给了终端用户,于是他们都玩不了游戏了!WTF!
数千名愤怒玩家要求快点修复这个问题。幸运的是,我们可以把代码回滚到上一个版本,而这花不了多长时间,但仍然需要查清楚是哪里出了问题。终我们发现是多个错误共同导致了这个问题,这在编程中很常见。
Microsoft Visual Studio 6(MSV6)中的有一个bug,而我们正是用的MSV6编译的游戏。对!不是我们的问题!自然,我们的测试无法找出问题。Whoops。
在特定的情况下,该编译器会在处理模板时生成错误的结果。模板是什么?它们很有用,但是会让你很头痛;有胆量的话看看这个。
C++是一个很复杂的编程语言,所以它的编译器有bug并不是什么奇怪的事情。实际上,C++比其它主流语言复杂得多,你可以看看C++和Ruby复杂度对比图。Ruby功能全面,所以很复杂,但如图所示,C++要复杂一倍,所以在其它一样的情况下,C++的bug也会多一倍。
在研究这个编译器的bug时,我们发现其实自己早知道这个bug,而且Microsoft dev团队已经在MSVC6 Service Pack 5(SP5)中修复了这个问题,所有的程序员都已经升级到了SP5。悲剧的是,我们忽略了构建服务器,而它是集合代码、插图、游戏地图、等组件,并终组成游戏的地方。所以,虽然游戏在每个程序员的计算机上能够正常运行,却在构建服务器上出了巨大的问题,因此也只有live分支有问题。
为什么只有live版本?嗯,理论上所有分支(dev、stage、live)同样有机会消除这样的bug,但实际上还是有区别的。首先,我们在live版本取消了很多编程和测试团队使用的调试功能,这样可以节省时间和金钱,但同样也会孕育出巨大的灾难,甚至导致游戏崩溃。
我们想确保ArenaNet和NCsoft的员工在游戏中没有作弊的机会,因为每个玩家都应该在一个公平的游戏平台上娱乐。很多MMO公司都曾有员工因使用“GM特权”而被开除的情况,因此我们想通过删除该功能来解决这个问题。
另外是我们清除了一些“sanity checking”代码,它们本是用于验证游戏是否在正常运行。这类代码被程序员称为断言(asserts or assertions),用来保证游戏状态在计算之后是合适并且正确的。断言会造成性能上的损失:每次例行检查都会花费时间;如果代码中嵌入了过多的断言,程序运行会变得缓慢。我们在live版本中禁用了断言以降低游戏服务器的CPU利用率,但无意间导致C++编译器生成了错误的结果,终造成游戏崩溃。
这个bug修复起来很简单,只需要升级下构建服务器可以了,但终我们决定保持断言是开启状态,即使在live版本中也是如此。为了保证不再出现这样的bug,我们放弃了节省CPU利用率(或者更准确地说,未来需要的计算机数)。
经验总结:每个人,包括程序员和构建服务器,都应该使用同样的工具!
也可能是你的计算机坏了
鉴于之前的bug误报,我实在是不好意思再向Microsoft提交bug报告了,开始怀疑是不是我或者其他组员的代码有问题。
在Guild Wars(GW)的开发期间,我接收到并且检查了很多玩家返回的bug信息。GW的玩家可能会记得(好不记得),当游戏崩溃时会提供向我们的“实验室”发送bug报告的信息供分析。收到这些信息后,我们会筛选bug并并决定由谁来处理。这些bug的原因、程度都各不相同,有的没有专人负责,而是我们轮流负责处理。
我们经常会遇到挑战信仰的bug,总是让人抓狂。bug的出现总是有原因的,我们首先可以假设可能的原因,并不涉及空间-时间统一性的重新定义。它看起来像是因为内存破坏或者线程竞争问题,但已知的信息告诉我们这不大可能。
Mike O’Brien,ArenaNet的联合创始人之一,也是一名骇客,终想到这可能是电脑硬件故障引起的,而不是编程问题。更重要的是,他还给出了测试这一假设的方法,简直是一个杰出的科学家。
他写了一个模块(“OsStress”),可以分配出一块内存,在那块内存中执行计算,然后和已知答案做比较。他把这块“压力测试”代码添加到主要的游戏循环中,这样每秒将执行30-50次这样的验证步骤。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11