《Effective Debugging:软件和系统调试的66个有效方法》——第3条:确保前置条件与后置条件都能够得到满足

第3条:确保前置条件与后置条件都能够得到满足

修理电子设备的时候,我们首先要检查供电是否正常,也就是检查电流有没有从电源模块正确地流入该设备的电路中。在很多情况下,这项检查都能帮助我们找出问题。计算机程序与之类似,很多问题也可以通过对例程的入口点(entry point)与出口(exit)进行检查而得以确定。入口点就是前置条件(precondition),它指的是程序在即将执行例程时所具备的状态,以及传递给该例程的输入值,出口则是后置条件(postcondition),它指的是程序执行完例程之后的状态及其返回值。如果前置条件得不到满足,那说明用来设置这些前置条件的代码里面有错误,若是后置条件得不到满足,则说明该例程本身有问题。如果两者都正确,那么应该转向其他地方去寻找bug。

我们可以在例程开始的地方、调用例程的地方或关键算法开始执行的地方设置断点(参见第30条)。为了判断前置条件是否得到满足,我们应该仔细检查算法的参数,包括传入的参数值,调用方法时所针对的对象,以及可疑代码所使用的全局状态。尤其要注意以下几点:

  • 找出那些本来不应为null,但实际上却为null的值。
  • 调用数学函数的时候,确保传入的值位于该函数的定义域之内,例如,调用log函数时传入的值应该大于0。
  • 查看对象、结构体与数组的内部细节,确保其内容符合要求。这也可以帮你查出无效的指针。
  • 检查变量的取值是否在合理范围之内。如果变量具有6.89851e-308或61007410这样的可疑取值,那通常表明它还没有初始化。
  • 检查传给例程的数据结构是否正确,例如,map有没有包含预期的键与值,双向链表(doubly linked list)能不能正确地遍历。

然后,我们应该在例程结束的地方、调用完例程的地方或关键算法执行完毕的地方设置断点,以判断该例程的执行效果是否正确:

  • 计算出来的结果看上去合理吗?有没有处在预期的范围之内?
  • 如果结果合理,而且位于预期的范围之内,那么实际的值是否正确?我们可以通过手算来演练相应的代码,以验证计算机的执行结果是否正确(参见第38条),也可以将执行结果与已知的正确值相对比,或是采用其他工具或方法来进行验算。
  • 例程的副作用是否符合预期?可疑代码所接触到的其他数据是否遭到破坏或拥有了不正确的取值?有些算法在遍历数据结构时,会把一些维护其工作所用的信息记录在数据结构中,对于这些算法来说,尤其应该进行这样的检查。
  • 算法所获得的资源,如文件句柄及锁,有没有正确地释放?

同样的方法也可以用在更为高层的操作与配置环境中。例如,如果要验证SQL语句是否正确地构建了某张表格,我们可以查看它所扫描的那些表格及视图,并且看看它构建出来的那张表格是什么样子。如果要判断基于文件的处理流程是否正确,我们可以检查其输入文件与输出文件。如果要调试某个构建在Web服务上面的操作,我们可以检查其中每项Web服务的输入与输出。如果要排解整个数据中心的故障,我们可以检查其中每个元素所需要的及所提供的机制是否正确,其中包括网络连接、DNS、共享存储、数据库以及中间件等。在这些情况下,我们都必须亲自验证(verify),而不能想当然地接受假设(assume)。

要点

  • 仔细检查例程的前置条件与后置条件。
时间: 2024-10-12 13:52:44

《Effective Debugging:软件和系统调试的66个有效方法》——第3条:确保前置条件与后置条件都能够得到满足的相关文章

《Effective Debugging:软件和系统调试的66个有效方法》一第3条:确保前置条件与后置条件都能够得到满足

第3条:确保前置条件与后置条件都能够得到满足 修理电子设备的时候,我们首先要检查供电是否正常,也就是检查电流有没有从电源模块正确地流入该设备的电路中.在很多情况下,这项检查都能帮助我们找出问题.计算机程序与之类似,很多问题也可以通过对例程的入口点(entry point)与出口(exit)进行检查而得以确定.入口点就是前置条件(precondition),它指的是程序在即将执行例程时所具备的状态,以及传递给该例程的输入值,出口则是后置条件(postcondition),它指的是程序执行完例程之后

《Effective Debugging:软件和系统调试的66个有效方法》——导读

前 言 我们在开发软件或对运行软件的系统进行管理的时候,经常会遇到故障.有些故障是因代码问题而引发的编译错误,这种故障可以在短时间内修复:还有一些故障则会使大型系统停机,这将给公司带来每小时数百万的损失(具体货币单位依情况而定).要想成为一名优秀的专业人士,你就必须在发生故障时迅速找出背后的原因并加以修复.这正是调试的意义所在,也是本书所要谈论的主题. 本书是写给有一定经验的开发者看的,而不是一本介绍性质的读物.它假设读者能够理解用各种编程语言所写成的代码片段,并且会使用高级的GUI编程工具以及

《Effective Debugging:软件和系统调试的66个有效方法》一导读

前 言 我们在开发软件或对运行软件的系统进行管理的时候,经常会遇到故障.有些故障是因代码问题而引发的编译错误,这种故障可以在短时间内修复:还有一些故障则会使大型系统停机,这将给公司带来每小时数百万的损失(具体货币单位依情况而定).要想成为一名优秀的专业人士,你就必须在发生故障时迅速找出背后的原因并加以修复.这正是调试的意义所在,也是本书所要谈论的主题. 本书是写给有一定经验的开发者看的,而不是一本介绍性质的读物.它假设读者能够理解用各种编程语言所写成的代码片段,并且会使用高级的GUI编程工具以及

《Effective Debugging:软件和系统调试的66个有效方法》一第6条:使用软件自身的调试机制

第6条:使用软件自身的调试机制 程序是一种很复杂的东西,因此它们通常都包含内置的调试机制.(至于怎样给自己正在开发的软件里面添加这样的机制,请参见第40条.)这种机制有很多好处,其中包括:我们可以通过禁用后台执行或多线程执行等特性来简化程序的调试工作.我们可以有选择地执行其中某一部分功能,以便通过测试用例来精确地再现相关的故障.程序可以给我们提供与性能有关的报表及其他信息.程序可以把更多的信息记录在日志文件中.因此,我们应该花一些时间,看看自己要调试的这款软件内置了哪些调试机制.想要了解这些机制

《Effective Debugging:软件和系统调试的66个有效方法》一第8条:把工作焦点放在最为重要的问题上

第8条:把工作焦点放在最为重要的问题上 许多大型软件系统都含有数量极其众多的bug(有一些是已知的bug,还有一些则尚未发现).要想高效地进行调试,就必须把应该受到关注的bug与可以忽略的bug明智地区分开.这样做不是为了单纯地缩减事务清单中的未决事务,而是为了帮助我们开发出稳定.易用.可维护而且效率较高的软件,毕竟这才是公司给我们支付薪水的原因.为此,我们要通过事务追踪系统来设定各项事务的优先级(参见第1条),从而使自己能够把工作重心汇聚在优先级较高的那些事务上,并把优先级较低的事务忽略掉.下

《Effective Debugging:软件和系统调试的66个有效方法》——第8条:把工作焦点放在最为重要的问题上

第8条:把工作焦点放在最为重要的问题上 许多大型软件系统都含有数量极其众多的bug(有一些是已知的bug,还有一些则尚未发现).要想高效地进行调试,就必须把应该受到关注的bug与可以忽略的bug明智地区分开.这样做不是为了单纯地缩减事务清单中的未决事务,而是为了帮助我们开发出稳定.易用.可维护而且效率较高的软件,毕竟这才是公司给我们支付薪水的原因.为此,我们要通过事务追踪系统来设定各项事务的优先级(参见第1条),从而使自己能够把工作重心汇聚在优先级较高的那些事务上,并把优先级较低的事务忽略掉.下

《Effective Debugging:软件和系统调试的66个有效方法》——第6条:使用软件自身的调试机制

第6条:使用软件自身的调试机制 程序是一种很复杂的东西,因此它们通常都包含内置的调试机制.(至于怎样给自己正在开发的软件里面添加这样的机制,请参见第40条.)这种机制有很多好处,其中包括: 我们可以通过禁用后台执行或多线程执行等特性来简化程序的调试工作. 我们可以有选择地执行其中某一部分功能,以便通过测试用例来精确地再现相关的故障. 程序可以给我们提供与性能有关的报表及其他信息. 程序可以把更多的信息记录在日志文件中. 因此,我们应该花一些时间,看看自己要调试的这款软件内置了哪些调试机制.想要了

《Effective Debugging:软件和系统调试的66个有效方法》一第13条:使自己尽可能多地观察到与调试有关的数据

第13条:使自己尽可能多地观察到与调试有关的数据 我们在调试的过程中要处理大量数据,并且要把各式各样的数据关联起来,如源代码.日志文件中的条目.变量的值.栈的内容.程序的I/O以及测试的结果等.这些数据通常是由多个处理流程与计算主机所产生的,如果能够把它们全都适当地展示在调试者眼前,那么将会给调试工作带来很多的好处.首先,可以使我们发现数据之间的相互关系.例如,我们可以看到:当测试失败的时候,日志文件中会多出来一条记录.其次,它可以令人尽量保持专注,避免因为来回切换而使思路受到干扰.有时我们必须

《Effective Debugging:软件和系统调试的66个有效方法》——第13条:使自己尽可能多地观察到与调试有关的数据

第13条:使自己尽可能多地观察到与调试有关的数据 我们在调试的过程中要处理大量数据,并且要把各式各样的数据关联起来,如源代码.日志文件中的条目.变量的值.栈的内容.程序的I/O以及测试的结果等.这些数据通常是由多个处理流程与计算主机所产生的,如果能够把它们全都适当地展示在调试者眼前,那么将会给调试工作带来很多的好处.首先,可以使我们发现数据之间的相互关系.例如,我们可以看到:当测试失败的时候,日志文件中会多出来一条记录.其次,它可以令人尽量保持专注,避免因为来回切换而使思路受到干扰.有时我们必须