软件调试的一般思路

来源:互联网 发布:威纶通触摸屏如何编程 编辑:程序博客网 时间:2024/05/16 11:22
解决软件的Bug就像警察破案一样。警察在掌握了案件发生的时间地点和相关人物后进行分析推理,采访相关人员,排除嫌疑人,最终找到凶手。同样的,软件开发人员在接到Bug时,也是分析Bug发生的背景,然后在运用各种方法来找出问题的原因。并不是所有的Bug都能一眼看出问题发生在哪个地方。虽然Bug发生的原因千差万别,但是我们还是有一些比较通用的方法来逐步缩小bug的根源的范围。在水缸里面抓鱼要比在河里面抓鱼要容易,同样的如果能把问题的根源缩小到一个类,一个函数,那么我们就能更容易找出Bug是如何发生的了。本文结合最近的一些经验以及阅读的一些资料,简单谈谈如何有效地找出问题的根源。

1. 哪些因素可能导致软件出现问题

简单来讲,导致软件出现问题的因素有如下几个方面:
  • 软件自身的问题
  • 第三方的问题,比如操作系统,第三方系统
  • 用户的输入

但最终来讲都是软件的问题,是软件本身没有处理好这些变化的因素。因此,在刚接到Bug的时候,我们可能无法立刻判断问题是由哪个因素引起的,谁都可能是凶手,因此我们要逐渐缩小怀疑的范围。

2. 利用实证来分析Bug

当问题出现了,我们可以根据看到的现象,结合问题发生的环境以及我们对软件逻辑的理解来分析推断出问题的原因。这当然是一种可行的方法,但是随着软件变得更加复杂,这并不是最有效的办法。软件调试相对于其他领域来讲还是比较容易的。比如,发生一起车祸以后,找出事故的原因只能靠分析,交警不能说事故现场没有发动机的日志,要求重现这个事故后再来分析事故的原因。而软件的优势就在于能做各种实验来证明你的想法。比如你怀疑是某个地方的问题,那么就去做个实验来看看。这就是利用实证的手段来分析Bug。它的一般步骤为:

  • 根据你对问题和软件的了解,提出一个假设,比如你怀疑问题可能是Windows 2012上特有的。
  • 根据你的假设,去构建实验来验证你的假设。同样,如果你怀疑问题是Windows 2012上特有的,那么可以做的实验之一就是到Windows 2008上去试一下,如果问题还是发生了,那就不能证明问题是2012上特有的。
  • 根据实验的结果,你能对问题有进一步的认识,从而能将问题的范围缩小。
需要注意的是:
  • 每次实验只能改变一个因素。假如某次实验和上个实现相比,你改变两个因素(比如既换了操作系统,又换了另外一个版本的软件),那么你就不知道这次实现的结果是由哪个因素引起的。
  • 每次做实验都要有个明确的目的,并且要有记录,包括变化了什么,结果是什么。要不然,过了一阵可能就忘记了。


3. 利用差异来缩小问题根源的范围

假如有两个“同样”配置的机器,一台有问题,另外一台没有问题,那么要找出那台有问题机器出问题的原因,可以关注一下两台机器有什么差别。虽然配置看起来一样,但他们肯定有差别。找出这些可能和问题相关的差别,利用上一节介绍的实证性分析的方法来证明你的假设。

另外一个例子,如果你开发中的软件,版本001没有问题,而版本002有问题,那么就看看这两个版本之间有什么差异,比如通过SCM来看看都改动了哪些文件,或者使用的第三方库是否发生了变化等。


4. 利用二分法

我们都知道二分查找的效率很高。同样我们也可以利用二分法的一般原理来缩小问题的范围。还是以上面的那个例子,假如版本001没问题,而版本008有问题,那么怎么快速找到问题是在哪个版本里面引入的呢。最直接的办法,从版本002一直试到008,但是这样效率就太低了。我们假设问题被引入后就不会自动消失,这样就可以利用二分法来找到查找问题被引入的第一个版本。我们先看版本005有没有同样的问题,如果有,那么问题就在版本002-004之间引入的,然后在继续用同样的方法找下去,最多找3次就能找到首次引入这个问题的版本,然后就可以看看那个版本里面有什么改动,就可以把问题的根源缩小到这些改动上了。

这也是持续集成的思想了,每次提交代码都会触发一次构建和单元测试。如果构建或者测试失败了,问题的的根源就是上一次代码提交造成的,在问题被引入的第一时间修复这个问题要比过了几个版本后再修复要容易一些。


5. 写出能重现问题的最短代码

如果软件的问题是由于第三方的库导致的,在向第三方库报告问题的时候,最好是能写出一个简单的程序来向其说明问题的发生条件,而不是把直接把你的软件的问题扔给第三方。

同样的,如果问题就是软件内部造成的,如果能写一个单元测试来重现问题,那么也能提高你测试和调试的速度,因为单元测试启动和运行的速度肯定比把整个系统启动起来的速度要快。任何时候,我们都要提高反馈的速度。


6. 小结

在遇到问题的时候要先分析以缩小问题根源的范围,而不是直接就跳到代码里面去看哪里出错了(那些一眼就看出问题出错的地方除外)。如果问题在某个环境(这里的环境是各种可能因素的组合,比如OS,软件,第三方库或者系统)发生了,而在另外的环境没有发生,利用这两个环境的差异来找出可能导致问题的因素。利用实证的方法来逐渐缩小问题根源的范围,利用二分法或者其他策略来快速排除一些干扰因素。在找到问题的根源后,最好能写出一个单元测试来重现问题,它能提高测试和调试的反馈速度,也有助于向第三方描述问题。我相信本文介绍的方法大家都曾经使用过,我只是将大家都知道的内容简单总结了一下,希望能有些帮助。


原文转载自:http://blog.csdn.net/jewes/article/details/8567792

原创粉丝点击