《Effective Debugging:软件和系统调试的66个有效方法》一第1条:通过事务追踪系统处理所有的问题

第1条:通过事务追踪系统处理所有的问题

请想象这样一种场景:George在电话里朝你大吼,说你开发的那个应用程序“运行不了”,于是你赶紧把问题写在便签上,然后把它贴在显示器旁边,显示器周围还有很多类似的纸条。现在你开始回想,自己到底有没有把新版程序所需的最新库文件发给George。实际上,我们不应该这样来处理问题,而是应该改用下面的办法。
首先,要保证有一套事务追踪系统(issue-tracking system)可供使用。很多开源软件库,如GitHub和GitLab等,都提供基本的事务追踪系统,该系统与它们所提供的其他功能是集成在一起的。有些组织使用一种名为JIRA的专有系统,这种系统要复杂得多,它可以在企业内部运行,也可以作为服务来运行。还有一些组织使用开源替代品,如Bugzilla、Launchpad、OTRS、Redmine或者Trac。选择哪个系统并不重要,重要的是必须保证所有的事务都记录在这个系统里面。
如果某个问题没有记录在事务追踪系统中,那我们就拒绝处理该问题。坚持使用这样的系统,能够带来下面几个好处:
可以看见调试工作所取得的进展。
可以对软件的发行进行追踪与规划。
帮助我们确定各种工作项(work item)之间的优先次序。
帮助我们把常见的事务及其解决方案整理成文档。
防止我们遗漏某些问题。
可以自动生成发行说明(release note)。
可以用作知识库,使我们对软件中的缺陷进行估量及反思,并从中总结经验。
对于公司里面那些不必亲自汇报问题的高层员工来说,你可以代他们汇报问题。如果某个问题是你自己发现的,那你也可以自己把这个问题提交到系统里面。有一些公司规定:在修改代码之前,必须先指明这次修改所涉及的事务。
我们还要保证的是:每一项事务都能够精确地描述问题的重现方式。最好能在其中给出一个简短(short)、自足(self-contained)且正确(correct,也就是可以正确编译并运行)的例子(example),即SSCCE。我们可以把这个例子直接剪下来,粘贴到应用程序中,以便重现它所要说明的问题(参见第10条)。为了使大家能够写出有效的错误报告(bug report),我们应该制订一份规范,并劝说所有人都认真遵照这份规范来撰写报告。(我看到有一家公司把这些规范贴在厕所门上。)
此外,错误报告还必须具备精确的标题(precise title),并写明bug的优先级(priority)、严重程度(severity)、受影响的利益相关者(stakeholder),以及该bug的发生情境(environment)。在填写这些内容时,要注意以下几点:
精准的标题使我们能够在事务汇总报告中迅速找出这个bug。用“程序崩溃”这几个字做标题是很糟糕的,应该改成“正在保存时单击刷新按钮,会使程序崩溃”。
严重程度能够帮助我们判断bug的优先级。与数据丢失有关的问题当然是很严重的,而另外一些无关紧要的问题,或是可以用某种明确的方式来绕过的问题,则显得不那么严重。团队可以根据bug的严重程度来对清单里面的各项事务进行分类,以决定哪些事务需要立刻解决,哪些可以稍后解决,哪些应该忽略。
对事务进行分类并排定其次序之后,就可以把结果填写在优先级这一栏中了,这使得我们能够据此安排各项事务的处理顺序(参见第8条)。在很多项目中,bug的优先级是由开发者或项目主管来设置的,如果允许终端用户来设置,那么他们总是会把自己提交的所有bug都设置成最高优先级。虽说管理人员、客户代表、其他团队的开发者以及销售人员都宣称自己提交的事务应该最先得到处理,但我们还是应该根据实际情况来设置优先级。
在事务中指出受到影响的利益相关者,可以帮助团队获知与该事务有关的其他一些信息,并帮助产品拥有者来决定事务的优先次序。有些公司甚至会在利益相关者后面标注他们给公司带来的年度收入。(例如,“由Acme所提交,该客户给公司带来的年度收入是25万元。”)
对于某些难以捕获的bug来说,情境描述可以提供线索,使得我们能够重现这种bug。不要强迫用户填写过多的信息,例如,PC的序列号、BIOS的日期,以及系统中每一个程序库的版本等,这样做会令用户觉得非常麻烦,从而跳过这些内容。我们只应该询问与bug密切相关的那些细节,对于Web应用程序来说,浏览器的信息自然是相当重要的,而对于移动应用程序来说,我们或许想知道设备的制造商及型号。如果能够通过软件来自动提交这些信息,那就更好了。
使用事务追踪系统时,我们一定要通过它来记录进度。大部分追踪系统都允许用户在每个事务后面持续追加各种形式的评论。这些文档可以把调查及修复bug时所经历的步骤记录下来,其中也可以包括修复bug时所遇到的困境。这样做可以使公司内的工作更加透明。我们应该精确地写出记录或追踪程序行为时所执行的各种命令,这样做很有用,因为明天你可能就要重新执行这些命令,你或你的同事也有可能要在一年之后寻找一个类似的bug。当你辛苦地完成了为期一周的bug搜寻工作之后,这些笔记可以帮助你回顾工作内容,使你能够更好地把这些天所做的事情解释给团队或管理者听。
要点
通过事务追踪系统来处理所有的问题。
确保每项事务都能够以短小、自足而又正确的范例(SSCCE),精确地描述出该问题的重现方式。
对事务进行分类,并根据每项事务的优先级与严重程度来安排工作。
通过事务追踪系统来记录进度。

时间: 2024-11-10 11:31:13

《Effective Debugging:软件和系统调试的66个有效方法》一第1条:通过事务追踪系统处理所有的问题的相关文章

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

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

《Effective Debugging:软件和系统调试的66个有效方法》——第7条:试着用多种工具构建软件,并将其放在不同的环境下执行

第7条:试着用多种工具构建软件,并将其放在不同的环境下执行 有时我们可以通过改变环境来锁定一些难以捕获的bug.例如,我们可以用另外一款编译器来构建这个软件,也可以切换到其他的运行时解释器.虚拟机.中间件.操作系统或CPU架构上.由于那些环境可能会更加严格地检查输入数据,或能通过其结构来凸现程序中的错误(参见第17条),因此可以帮助我们发现原来很难找到的一些bug.如果程序不够稳定.总是发生无法重现的崩溃问题,或移植起来不太顺利,那就应该试着把它放在另外一种环境下进行测试,这使得我们能够使用更为

《Effective Debugging:软件和系统调试的66个有效方法》——第15条:查看第三方组件的源代码,以了解其用法

第15条:查看第三方组件的源代码,以了解其用法 我们所要调试的代码之所以会出bug,通常并不是由于它使用的第三方程序库或应用程序本身有问题(参见第14条),而是因为它使用这些第三方组件时所采取的方式有误. 这种情况并不令人惊讶,由于这些软件本身是作为黑盒来与你所写的代码进行集成的,因此,你不太可能在它们之间相互协调.对于这类问题来说,有一个很有用的办法,就是去查看第三方程序库.中间件甚至是底层软件的源代码. 首先,如果想查明某个API为什么没有像你所期望的那样运作,或是想查明某条奇怪的错误消息是

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

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

《Effective Debugging:软件和系统调试的66个有效方法》——第2条:在网上确切地查询你所遇到的问题,以寻求解决问题的灵感

第2条:在网上确切地查询你所遇到的问题,以寻求解决问题的灵感 现在很少有哪个工作场所不能上网,如果在一个无法上网的地方开发程序,那我的效率会很低.遇到代码错误的时候,我们应该上网搜索,或者与同事一起寻找解决办法. 有一个相当有效的搜索技巧,是把由第三方组件所给出的错误消息打上双引号,并将其粘贴到浏览器的搜索框里面.把待搜索的内容放在一对双引号中,意思是要告诉搜索引擎:只搜索与该内容精确匹配的页面.这样做可以使搜索结果更加准确.还有一个很有用的技巧,是把与错误有关的程序库或中间件的名称.对应的类名

《Effective Debugging:软件和系统调试的66个有效方法》——第5条:在能够正常运作的系统与发生故障的系统之间寻找差别

第5条:在能够正常运作的系统与发生故障的系统之间寻找差别 我们通常都能够同时访问这样两个系统,其中一个是发生故障的系统,另一个是与之相似但却可以正常运行的系统.当我们实现了某项新功能.更新了某些工具或基础组件,或是把系统部署在某个新的平台上面时,就可能会遇到新系统无法正常运行的问题,此时如果旧系统依然正常,那么我们通常可以通过寻找(下面就会讲到如何寻找)或尽量缩小(参见第45条)新旧两个系统之间的差别来锁定问题的原因. 之所以能根据新旧系统间的差距来进行调试,其原因在于:尽管各人所经历的问题有所

《Effective Debugging:软件和系统调试的66个有效方法》——第10条:高效地重现程序中的问题

第10条:高效地重现程序中的问题 要想高效地调试程序问题,一个关键的因素就是要能够可靠且方便地重现它.这么说有三个理由.首先,如果我们总是能做到只按一个按钮就可以重现问题,那么自然能够专心地去寻找问题的原因,而不用再浪费时间去研究怎样才能把这个问题重现一遍.第二,如果我们可以方便地重现问题,那么也就能够同样方便地把问题描述出来,以寻求外人的帮助(参见第2条).第三,修复错误之后,我们可以把重现问题所需的步骤执行一遍,如果程序这次没有出现故障,那就证明我们对其所做的修复是正确的. 创建短小的范例或

《Effective Debugging:软件和系统调试的66个有效方法》——第11条:修改完代码之后,要能够尽快看到结果

第11条:修改完代码之后,要能够尽快看到结果 调试通常是一种循序渐进的过程.在每一轮中,我们都要花时间去构建并运行软件,而且要看着它发生故障,这些环节会占用很多时间,而且这些时间并没有用来解决软件中的问题.因此,我们要提前进行准备,设法缩短每一轮调试所花费的时间. 首先从软件的构建入手.我们应该能通过一条命令(如make或mvn compile)或一个按键(如F5)把发生故障的软件迅速构建出来.构建过程应该能够记录文件之间的依赖关系,使得我们在修改了某处代码之后只有少数几个文件需要重新编译.能够

《Effective Debugging:软件和系统调试的66个有效方法》——第19条:使调试任务自动化

第19条:使调试任务自动化 我们或许会找到很多个与程序错误有关的因素,但是却没有办法轻易推断出究竟哪一个因素才是致使程序出错的真正原因.为了把这个原因找出来,我们可以编写一小段例程或脚本,把有可能使程序出错的所有情况全都搜索一遍.如果待搜索的情况比较多,不便于手工进行搜索,但是却能够通过循环来进行遍历,那么就可以考虑对其加以自动化.例如,如果想遍历的是500个字符,那么可以通过自动化的脚本来实现,然而如果要把用户可能会输入的所有字符串全都尝试一遍,那么采用自动化脚本就不太合适了. 下面举一个例子

《Effective Debugging:软件和系统调试的66个有效方法》——第16条:使用专门的监测及测试设备

第16条:使用专门的监测及测试设备 调试嵌入式系统及系统软件的时候,我们可能要对从硬件到应用程序的整个计算栈进行分析.调试工作一旦深入硬件层面,我们就需要关注电流的微小变化以及磁矩的对齐情况等细节.在大多数情况下,可以通过强大的IDE以及一些追踪软件与日志记录软件来探查这些问题,然而有的时候,就连这些工具也帮不上忙.这通常发生在软件与硬件有所接触的场合,也就是说,虽然你认为你所写的软件能够像预期的那样运作,但是硬件却有着它自己的处理方式.例如,你把正确的数据写入磁盘,再将其读取出来,却发现这些数