所属文章系列及序号:寻找尘封的银弹:bug修理厂(一)
看似没有什么营养的bug描述里,其实蕴含着两个关键要素,往往被我们忽略。开发者一旦掌握了这两个要素,灵感会被瞬间激发出来,立刻想到解决方案,而且是正确的方案!笔者之所以要在这里强调“正确的方案”,原因就在下边对这两个要素的讲述之中。
【一个要素是条件】
Bug描述里一般会列出这些条件:操作系统的版本号,环境变量配置了什么值(这些变量也许会是一个长长的列表),发生bug之前做了什么操作(这些操作也许会是一个长长的列表)。
我们需要从这个描述中找出导致bug的“条件要素”,才能更好的理解bug发生的原因,从而可以找到解决方案。这里提到的“条件要素”是指,如果不执行某个测试步骤,就不会发生这个bug,那么这个步骤就是“条件要素”。
对于能够100%重现bug(或叫必现),我们既可以用下边的方法去找“条件要素”,又可以直接用设置断点的方式去发现代码错误,不过设置哪个断点也有很多可讨论的地方,这些复杂的讨论需要在开发者“做bug重现”时再去解决(参见后续文章)。在这两种方法的具体选择上,要看哪个方法更快、自己更熟悉等因素。
对于重现概率较低的bug,作为一个开发者,如何在这些海量信息面前,迅速找出那个决定性的条件?这绝对是个能力,而且有时很像智商测试题。这是程序员必备的技能,具体的方法有很多,其中一个方法是“对比”。
现代版的俗话说:“没有对比就没有伤害”。
当开发者或测试者修改了某一个测试步骤,例如改变了一个环境变量的值、减少了一个测试步骤、改变了两个测试步骤的顺序,等等,有时就会发现bug没有了,那就证明是这次的测试步骤改变导致bug消失的,条件要素也就找到了。
这里有两个变化需要注意:
一、无论是必现的bug还是不必现的bug,修改一个步骤后bug消失了,一般情况下就能判断出是这次修改步骤导致的,但仅限于一般情况,还有其他情况导致bug发生,例如多线程,这些复杂的讨论需要在开发者“做bug重现”时再去解决(参见后续文章),这个阶段只是为了让项目经理、开发者、测试者看懂bug就足够做决策用了。
二、一次只能改变一个测试步骤,否则我们就无法准确知道是哪个改变导致的。
到此为止,方法是有了,但是方法还不够有力。一旦测试步骤非常多,那么需要对比的测试用例就多,有时会达到100条以上,这样的效率就太低了,而且操作起来让人心烦,根本找不到工作中的快乐。
好在我们还有更好的方法:谷歌搜索的“手气不错”!也就是说,在把所有情况罗列出来以前,先用自己的直觉试验一个最有可能的用例,往往就能找到那个关键的条件要素。不过直觉需要知识和经验的积累,更需要对经验的“反刍”。
【另一个要素是“错误是什么”】
有人会说,“错误是什么”不是明摆着的吗?看完下边这个例子,他就能体会到“明摆着”只是一种奢望:
有一个Bug的标题是:用户打开某个界面时,得到的人员列表不符合预期。
Bug的细节描述是:当用户打开应用程序的一个界面时,得到了一个如下这个不符合预期的人员列表:
002 B先生
003 C小姐
001 A先生
而期望值是:
001 A先生
002 B先生
003 C小姐
理解错误的坏结果
如果这个列表比较长,那么靠人眼去对比期望值和实际结果,需要多花一点时间。不要小看多花的这一点时间,一方面,人的大脑看到琐碎的东西一定会比较累。
另一方面,如果是产品经理或项目经理在看这个列表,他不可能去看每一个bug的细节,因为他需要站在一个更高的视角去看待整个项目。所以他看到这种模糊不清的问题,要么多花一些时间去仔细理解这个bug,要么是认为自己理解清楚了,从而让这个bug在整个开发链条中的多个人之间流转一圈,最后bug仍然没有解决,这样一来,多花的时间就有些可观了。
导致理解错误的浅层原因
下面就是一个导致bug无效流转的“坑”。
开发者看到这个结果对比的直觉是:一定是第一列的显示顺序错了。之后,开发者就去改代码,改完之后,测试者又发现了另外一个bug:
当用户打开应用程序的一个界面时,得到了一个如下列表:
001 A先生
002 B先生
003 C小姐
004 A小姐
而期望值是:
001 A先生
004 A小姐
002 B先生
003 C小姐
实际上只是因为在这个列表中又加入一条数据而已,却触发了开发者改上一个bug时的理解错误,导致修改bug的成本翻倍。
经过分析,终于得出结论:应该按照第二列排序,而不是第一列!
这还只是一个最简单的例子,大部分人还是能一眼就能看出来,但是,实际的工作中远比这个情况复杂,想不“中招”就需要去芜取精的能力了。
正确的做法是:
开发者看到这个问题,如果逻辑清晰的话,应该能想到有很多种情况导致这种错误,上文提到的只是其中的两种情况,他想到之后要去找测试者确认,有时甚至要找到需求文档编写者和产品经理。
导致理解错误的深层原因
表面上看起来这是个沟通问题,其实不是,这是因为:测试者确切地知道需求是什么,只是他认为没必要写出来,而开发者也认为自己理解对了,也就没必要再问,导致了bug的无效流转。当大家都认为没有分歧时,自然就不需要沟通,所以逻辑能力的欠缺才是深层原因!
解决逻辑能力欠缺的有效方法有两个:长期来看,应该去学习、思考。短期来看,用最准确的语言去描述,例如上文的bug描述应改为:用户打开某个界面时,得到的人员列表应该按照第二列排序。
导致理解错误的知识原因
行文至此,如果读者认为这就是“第二个要素:错误是什么”的全部了,“也不过如此嘛”,那有时还会掉到下边这个更深的“坑”里:
对于使用分布式数据库的系统,程序中传给数据库的SQL中,如果没有包含order by,那得到数据的顺序是不会得到保证的!因为分布式数据库为了提高性能,是用并发的方式从多个数据库节点获得数据,既然是并发,那就无法确定哪个节点的数据先传到。
如果开发者没有这个知识,或即便有这个知识而忘记了在这里运用它,就会掉到上边这个“深坑”里。结果就是:让一个bug衍生出另外一个bug,再衍生出第三个bug,让这些“臭虫”在开发者、测试者、项目经理、产品经理,甚至客户那里转啊转,创造出的GDP是很多了,但都是无价值甚至是负价值的GDP。
作于2018-3-10