描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787111568896丛书名: Effective系列丛书
内容简介
本书共分8章。首先讲解调试策略(第1章)、调试方法(第2章)以及调试时所用的工具与技巧(第3章),这些知识使我们能够应对各种软件故障及系统故障。接下来讨论在调试工作的各个阶段所用到的具体技巧,也就是在使用调试器(第4章)、编写程序(第5章)、编译软件(第6章)以及运行系统(第7章)时所用到的调试技巧。与多线程和并发有关的bug是很难寻找的,所以本书后专门用一章(第8章)来讲解特定的调试工具及调试技术,使大家能够找出这些bug。
目 录
Contents 目 录
译者序
前言
致谢
第1章 宏观策略 1
第1条:通过事务追踪系统处理所有的问题 1
第2条:在网上确切地查询你所遇到的问题,以寻求解决问题的灵感 4
第3条:确保前置条件与后置条件都能够得到满足 6
第4条:从具体问题入手向上追查bug,或从高层程序入手向下追查bug 7
第5条:在能够正常运作的系统与发生故障的系统之间寻找差别 9
第6条:使用软件自身的调试机制 13
第7条:试着用多种工具构建软件,并将其放在不同的环境下执行 16
第8条:把工作焦点放在为重要的问题上 20
第2章 通用的方法与做法 23
第9条:相信自己能够把问题调试好 23
第10条:高效地重现程序中的问题 26
第11条:修改完代码之后,要能够尽快看到结果 29
第12条:将复杂的测试场景自动化 30
第13条:使自己尽可能多地观察到与调试有关的数据 32
第14条:考虑对软件进行更新 34
第15条:查看第三方组件的源代码,以了解其用法 35
第16条:使用专门的监测及测试设备 37
第17条:使故障更加突出 40
第18条:从自己的桌面计算机上调试那些不太好用的系统 42
第19条:使调试任务自动化 44
第20条:开始调试之前与调试完毕之后都要把程序清理干净 46
第21条:把属于同一个类型的所有问题全都修复好 47
第3章 通用的工具与技术 49
第22条:用Unix命令行工具对调试数据进行分析 49
第23条:掌握命令行工具的各种选项及习惯用法 55
第24条:用编辑器对调试程序时所需的数据进行浏览 57
第25条:优化工作环境 59
第26条:用版本控制系统寻找bug发生的原因及经过 64
第27条:用工具监测由多个独立程序所构成的系统 67
第4章 调试器的使用技巧 71
第28条:编译代码时把符号信息包含进来,以便于调试 72
第29条:对代码进行单步调试 76
第30条:设置代码断点和数据断点 77
第31条:了解反向调试功能 80
第32条:查看例程之间的相互调用情况 83
第33条:查看变量及表达式的值,以寻找程序中的错误 84
第34条:了解怎样把调试器连接到正在运行的进程上 87
第35条:了解怎样运用核心转储信息来进行调试 89
第36条:把调试工具设置好 92
第37条:学会查看汇编代码及原始内存 95
第5章 编程技术 100
第38条:对可疑的代码进行评审,并手工演练这些代码 100
第39条:审读代码并与同事讨论 102
第40条:给软件添加调试机制 103
第41条:添加日志语句 107
第42条:对软件进行单元测试 111
第43条:用断言进行调试 114
第44条:改动受测程序,以验证自己的推想 118
第45条:尽量缩小正确范例与错误代码之间的差距 119
第46条:简化可疑代码 120
第47条:将可疑代码改用另外一种编程语言来写 123
第48条:改善可疑代码的可读性与结构 124
第49条:要清除bug的根源,而不仅仅消除其症状 128
第6章 编译时的调试技术 130
第50条:对生成的代码进行检视 130
第51条:使用静态程序分析工具 133
第52条:对项目进行配置,令程序能够以固定的方式构建和执行 138
第53条:对调试所用程序库及构建代码时所应执行的检查进行配置 141
第7章 运行时的调试技术 147
第54条:通过构建测试用例来寻找错误 147
第55条:令软件在遇到问题时尽早退出 151
第56条:检视应用程序的日志文件 152
第57条:对系统和进程所执行的操作进行性能评测 156
第58条:追踪程序的执行情况 160
第59条:使用动态程序分析工具 166
第8章 调试多线程的代码 169
第60条:通过事后调试来分析死锁问题 169
第61条:捕获并重现 176
第62条:用专门的工具来探查死锁与竞争条件问题 180
第63条:把不确定的因素隔离出来,或将其移除 186
第64条:检查资源争用情况,以解决与可伸缩性有关的问题 188
第65条:用性能计数器寻找伪共享问题 191
第66条:考虑用更为高级的抽象机制来重写代码 195
网上资源 203
译者序
前言
致谢
第1章 宏观策略 1
第1条:通过事务追踪系统处理所有的问题 1
第2条:在网上确切地查询你所遇到的问题,以寻求解决问题的灵感 4
第3条:确保前置条件与后置条件都能够得到满足 6
第4条:从具体问题入手向上追查bug,或从高层程序入手向下追查bug 7
第5条:在能够正常运作的系统与发生故障的系统之间寻找差别 9
第6条:使用软件自身的调试机制 13
第7条:试着用多种工具构建软件,并将其放在不同的环境下执行 16
第8条:把工作焦点放在为重要的问题上 20
第2章 通用的方法与做法 23
第9条:相信自己能够把问题调试好 23
第10条:高效地重现程序中的问题 26
第11条:修改完代码之后,要能够尽快看到结果 29
第12条:将复杂的测试场景自动化 30
第13条:使自己尽可能多地观察到与调试有关的数据 32
第14条:考虑对软件进行更新 34
第15条:查看第三方组件的源代码,以了解其用法 35
第16条:使用专门的监测及测试设备 37
第17条:使故障更加突出 40
第18条:从自己的桌面计算机上调试那些不太好用的系统 42
第19条:使调试任务自动化 44
第20条:开始调试之前与调试完毕之后都要把程序清理干净 46
第21条:把属于同一个类型的所有问题全都修复好 47
第3章 通用的工具与技术 49
第22条:用Unix命令行工具对调试数据进行分析 49
第23条:掌握命令行工具的各种选项及习惯用法 55
第24条:用编辑器对调试程序时所需的数据进行浏览 57
第25条:优化工作环境 59
第26条:用版本控制系统寻找bug发生的原因及经过 64
第27条:用工具监测由多个独立程序所构成的系统 67
第4章 调试器的使用技巧 71
第28条:编译代码时把符号信息包含进来,以便于调试 72
第29条:对代码进行单步调试 76
第30条:设置代码断点和数据断点 77
第31条:了解反向调试功能 80
第32条:查看例程之间的相互调用情况 83
第33条:查看变量及表达式的值,以寻找程序中的错误 84
第34条:了解怎样把调试器连接到正在运行的进程上 87
第35条:了解怎样运用核心转储信息来进行调试 89
第36条:把调试工具设置好 92
第37条:学会查看汇编代码及原始内存 95
第5章 编程技术 100
第38条:对可疑的代码进行评审,并手工演练这些代码 100
第39条:审读代码并与同事讨论 102
第40条:给软件添加调试机制 103
第41条:添加日志语句 107
第42条:对软件进行单元测试 111
第43条:用断言进行调试 114
第44条:改动受测程序,以验证自己的推想 118
第45条:尽量缩小正确范例与错误代码之间的差距 119
第46条:简化可疑代码 120
第47条:将可疑代码改用另外一种编程语言来写 123
第48条:改善可疑代码的可读性与结构 124
第49条:要清除bug的根源,而不仅仅消除其症状 128
第6章 编译时的调试技术 130
第50条:对生成的代码进行检视 130
第51条:使用静态程序分析工具 133
第52条:对项目进行配置,令程序能够以固定的方式构建和执行 138
第53条:对调试所用程序库及构建代码时所应执行的检查进行配置 141
第7章 运行时的调试技术 147
第54条:通过构建测试用例来寻找错误 147
第55条:令软件在遇到问题时尽早退出 151
第56条:检视应用程序的日志文件 152
第57条:对系统和进程所执行的操作进行性能评测 156
第58条:追踪程序的执行情况 160
第59条:使用动态程序分析工具 166
第8章 调试多线程的代码 169
第60条:通过事后调试来分析死锁问题 169
第61条:捕获并重现 176
第62条:用专门的工具来探查死锁与竞争条件问题 180
第63条:把不确定的因素隔离出来,或将其移除 186
第64条:检查资源争用情况,以解决与可伸缩性有关的问题 188
第65条:用性能计数器寻找伪共享问题 191
第66条:考虑用更为高级的抽象机制来重写代码 195
网上资源 203
前 言
Preface 前 言我们在开发软件或对运行软件的系统进行管理的时候,经常会遇到故障。有些故障是因代码问题而引发的编译错误,这种故障可以在短时间内修复;还有一些故障则会使大型系统停机,这将给公司带来每小时数百万的损失(具体货币单位依情况而定)。要想成为一名优秀的专业人士,你就必须在发生故障时迅速找出背后的原因并加以修复。这正是调试的意义所在,也是本书所要谈论的主题。
本书是写给有一定经验的开发者看的,而不是一本介绍性质的读物。它假设读者能够理解用各种编程语言所写成的代码片段,并且会使用高级的GUI编程工具以及基于命令行的编程工具。另一方面,我会在书中详细描述调试技巧,因为我发现:即便是对某些开发方法很有经验的编程专家,也依然需要一些手把手的指导,才能够掌握其他的开发方法。此外,如果你已经花了至少几个月时间来调试一些颇具规模的软件,那么应该会更容易理解书中某些高级技巧所适用的场合。
本书所涵盖的范围本书所要讲解的调试知识,包括与调试有关的策略、工具及方法。我们当前在开发并运作一款复杂的计算系统时,可能会遇到各种问题,而这些调试知识,则使大家能够应对这些问题。过去我们所说的调试,主要是指检测并修复程序错误,而当前却很少有哪个程序会孤立地运作,即便是一个很小的程序,也会与外部的程序库相链接(通常是动态链接)。更为复杂的程序会运行在应用程序服务器中,会调用Web服务,会使用关系型数据库及NoSQL数据库,会从目录服务器上获取数据,会运行外部的程序,会利用其他的中间件,也会纳入很多第三方的软件包。于是,要想令整个系统及服务正常地运作,就必须确保其中的组件不会发生故障,这些组件可能是由公司内部人员所开发的,也可能是由第三方所提供的,它们所在的主机或许分布在全球各地。为了应对这种局面,软件开发行业开始重视DevOps规程,这套规程旨在同时强调开发者和其他IT专业人员所应担负的职责。与之类似,本书想使读者在面对故障时也能够具备这样一种全面的观念,因为在面对一些极为困难的问题时,我们通常无法立刻判断出该问题到底是由哪一个软件组件所引发的。
本书的内容按照从一般到特殊的顺序来进行安排。首先讲解调试策略(第1章)、调试方法(第2章)以及调试时所用的工具与技术(第3章),这些知识使我们能够应对各种软件故障及系统故障。接下来,讨论在调试工作的各个阶段所用到的具体技巧,也就是在使用调试器(第4章)、编写程序(第5章)、编译软件(第6章)以及运行系统(第7章)时所用到的调试技巧。与多线程和并发有关的bug是很难寻找的,所以后我们专门用一章(第8章)来讲解特定的调试工具及调试技术,使大家能够找出这些bug。
怎样运用书中的内容你可以从页读起,一页一页往后翻,直到看完。但是别急,其实还有更好的读法。书里给出的建议可以分成以下三种。
策略与方法。这些内容包括我们在面对故障时所应具备的知识以及所应采取的做法。本书第1章和第2章里面的内容就属于这一类,此外,第5章中的很多技巧也可以归入此类。阅读并理解了这些内容之后,你需要在工作中对其加以运用,以便逐渐养成习惯。调试程序的时候,我们需要系统地反思自己所用的办法,如果某个办法行不通,那就应该把自己所经历的路线回顾一遍,这样可以帮助我们发现解决该问题的其他办法。
技巧与工具。这些内容值得大家投入时间去学习,它们主要出现在第3章里面,其他章节中的某些内容(如第36条)也同样可以归为这一类,我们可以在日常工作中运用这些内容来解决问题。大家应该花时间去学习这些内容,并且要逐步实践它们。这或许意味着我们要放弃自己所熟悉的调试工具,而去使用一些学习曲线较为陡峭但是功能上更加先进的调试工具,那些工具虽然一开始学起来比较困难,可是从长远来看,却能够帮助你成为调试方面的专家。
调试的思路。当我们遇到困难时,可以根据这些思路来找寻合适的技巧。这些内容不一定每天都会用到,但是当你遇到一个琢磨不透的问题时,它可以帮助你节省一整天(或者说至少几小时)的时间。比如,如果你不清楚自己所写的C和C 代码为什么无法编译,那么第50条或许能给你一些启发。大家应该快速浏览这些内容,使自己意识到它们可以在某些场合派上用场,等到真正需要使用它们的时候,再去详细研究。
本书对软件开发的其他方面所起的作用本书里的所有条目都是针对故障的诊断与调试而写的,不过其中有很多建议同样可以用来缩减代码中的bug数量,并且可以使你在遇到这样的bug时能够更为迅速地将其修复。严谨的调试技术与优秀的软件开发方式之间能够形成良性的循环,因此,书中的建议对于你当前或者将来要面对的软件设计、软件构建以及软件管理工作,是可以起到帮助作用的。
设计软件的时候,应该遵循下列建议:
使用与其角色相称的高级机制(参见第47条和第66条)。
提供调试模式(参见第6条和第40条)。
提供对系统操作进行监控与记录的机制(参见第27条、第41条和第56条)。
提供一个选项,使得开发者可以用Unix命令行工具来编写与组件有关的脚本(参见第22条)。
把内部的错误暴露出来,使其表现为软件故障,而不要将其隐藏起来,使其成为软件中的不稳定因素(参见第55条)。
提供一种方式,使得开发者能够在软件发生故障之后获得内存转储(memory dump)信息(参见第35条和第60条)。
从数量和范围方面,尽量缩减软件在执行时的不确定因素(参见第63条)。
构建软件的时候,应该遵循下列建议:
征求同事的意见(参见第39条)。
为你所编写的每个例程创建单元测试(参见第42条)。
用断言来验证自己所做的假设是否成立,以及代码的功能是否正确(参见第43条)。
尽量把代码写得易于维护,也就是要写出易读、稳定且便于分析和修改的代码(参见第46条和第48条)。
在构建程序时避免不确定的因素(参见第52条)。
在对软件的开发及运作进行管理时,应该遵循下列建议(无论是要管理一个团队,还是只管理自己的流程):
用适当的事务追踪系统,把遇到的问题记录下来(参见第1条)。
对各种有待处理的事务进行分类,并排定其优先次序(参见第8条)。
把对软件所做的修改适当地记录在修订管理系统中,并且对该系统进行较好的维护(参见第26条)。
渐进地部署软件,使得我们可以在新旧版本之间进行对比(参见第5条)。
尽量采用各种不同的工具来开发,并试着把程序部署在各种环境中(参见第7条)。
经常对工具与程序库进行更新(参见第14条)。
如果使用了第三方的程序库,那么可以考虑购买该程序库的源代码(参见第15条);考虑购买一些较为完善的工具来锁定那些不太容易找到的错误(参见第51条、第59条、第62条、第64条及第65条)。
寻找专门的工具来调试硬件接口及嵌入式系统(参见第16条)。
使得开发者能够远程调试软件(参见第18条)。
对于消耗资源较多的故障诊断任务来说,要留出足够的CPU及磁盘资源(参见第19条)。
鼓励开发者之间通过代码评审及编程指导等手段进行协作(参见第39条)。
鼓励大家进行测试驱动开发(参见第42条)。
在构建软件的时候,要做性能分析、静态分析以及动态分析(参见第57条、第51条及第59条),并且要打造一套迅速而高效的构建流程与测试流程(参见第53条及第11条)。
对书中术语的说明本书所说的fault(错误)一词,遵循ISO-24765—2010(Systems and software engi-neering——Vocabulary)标准,它的意思是:“计算机程序里面某个不正确的步骤、流程或数据定义。”这也称为defect(缺陷)。在日常工作中,我们把这叫做bug。与之类似,本书所用的failure(故障)一词,也遵循ISO-24765—2010标准,它指的是:“因系统或系统组件未能在规定限制之下执行所需功能而引发的事件。”故障可以表现为程序崩溃、程序冻结或是程序的结果有误。故障一词强调的是程序运行的后果,而错误一词强调的则是我们所遇到或使用的某个程序本身有问题。不过有的时候,大家也会用错误及缺陷这两个词来指代故障,ISO标准也承认了这一点。笔者在本书中会按照上述定义来区分这几个词,然而在语境比较明确的情况下,我通常也会用问题(problem)一词来指代错误(如“代码有问题”)或故障(如“可以重现的问题”),这样写能够使本书读起来更加流畅,而不至于变成一份法律文件。
Unix操作系统的shell、程序库以及工具,目前都可以运行在各种各样的平台上。笔者采用Unix一词来指代遵从Unix原则及API的任何一种系统,包括Apple的Mac OS X、各种GNU/Linux发行版(如Arch Linux、CentOS、Debian、Fedora、openSUSE、Red Hat Enterprise Linux、Slackware及Ubuntu)、直接从Unix继承而来的系统(如AIX、HP-UX及Solaris)、各种BSD衍生系统(如FreeBSD、OpenBSD及NetBSD),以及运行在Windows系统上的Cygwin。
本书中所列出的C 、Java或Python代码,针对的也是较新的编程语言版本,不过笔者会避开那些奇怪的或是刚刚推出的特性。
书里面会出现“你的代码”和“你的软件”这两种说法,它们指的是你正在调试的代码以及正在开发的软件。这两种说法听起来比较简洁,而且也暗含了一种对代码所有权的宣示,这对于软件开发人员来说是十分重要的。
笔者所说的例程(routine)一词,是指可供调用的代码单元,如成员函数、方法、函数、过程以及子例程等。
Visual Studio及Windows指的是Microsoft公司的相关产品。
修订控制系统(revision control system)及版本控制系统(version control system),是指像Git这样能够对软件配置进行管理的工具。
排版约定Unix命令行选项使用–this这样的形式,与该选项等价的单字母选项使用-t这样的形式。Windows工具中的对应选项,使用/this这样的形式。
按键采用Shift-F11这样的形式。
文件路径采用/etc/motd这样的形式。
菜单操作采用Debug-New Breakpoint-Break at Function这样的形式。
为了缩短篇幅,笔者会省略C 代码中的std::限定符及std名称空间。
描述GUI(图形用户界面)工具时,笔者所说的功能针对的
本书是写给有一定经验的开发者看的,而不是一本介绍性质的读物。它假设读者能够理解用各种编程语言所写成的代码片段,并且会使用高级的GUI编程工具以及基于命令行的编程工具。另一方面,我会在书中详细描述调试技巧,因为我发现:即便是对某些开发方法很有经验的编程专家,也依然需要一些手把手的指导,才能够掌握其他的开发方法。此外,如果你已经花了至少几个月时间来调试一些颇具规模的软件,那么应该会更容易理解书中某些高级技巧所适用的场合。
本书所涵盖的范围本书所要讲解的调试知识,包括与调试有关的策略、工具及方法。我们当前在开发并运作一款复杂的计算系统时,可能会遇到各种问题,而这些调试知识,则使大家能够应对这些问题。过去我们所说的调试,主要是指检测并修复程序错误,而当前却很少有哪个程序会孤立地运作,即便是一个很小的程序,也会与外部的程序库相链接(通常是动态链接)。更为复杂的程序会运行在应用程序服务器中,会调用Web服务,会使用关系型数据库及NoSQL数据库,会从目录服务器上获取数据,会运行外部的程序,会利用其他的中间件,也会纳入很多第三方的软件包。于是,要想令整个系统及服务正常地运作,就必须确保其中的组件不会发生故障,这些组件可能是由公司内部人员所开发的,也可能是由第三方所提供的,它们所在的主机或许分布在全球各地。为了应对这种局面,软件开发行业开始重视DevOps规程,这套规程旨在同时强调开发者和其他IT专业人员所应担负的职责。与之类似,本书想使读者在面对故障时也能够具备这样一种全面的观念,因为在面对一些极为困难的问题时,我们通常无法立刻判断出该问题到底是由哪一个软件组件所引发的。
本书的内容按照从一般到特殊的顺序来进行安排。首先讲解调试策略(第1章)、调试方法(第2章)以及调试时所用的工具与技术(第3章),这些知识使我们能够应对各种软件故障及系统故障。接下来,讨论在调试工作的各个阶段所用到的具体技巧,也就是在使用调试器(第4章)、编写程序(第5章)、编译软件(第6章)以及运行系统(第7章)时所用到的调试技巧。与多线程和并发有关的bug是很难寻找的,所以后我们专门用一章(第8章)来讲解特定的调试工具及调试技术,使大家能够找出这些bug。
怎样运用书中的内容你可以从页读起,一页一页往后翻,直到看完。但是别急,其实还有更好的读法。书里给出的建议可以分成以下三种。
策略与方法。这些内容包括我们在面对故障时所应具备的知识以及所应采取的做法。本书第1章和第2章里面的内容就属于这一类,此外,第5章中的很多技巧也可以归入此类。阅读并理解了这些内容之后,你需要在工作中对其加以运用,以便逐渐养成习惯。调试程序的时候,我们需要系统地反思自己所用的办法,如果某个办法行不通,那就应该把自己所经历的路线回顾一遍,这样可以帮助我们发现解决该问题的其他办法。
技巧与工具。这些内容值得大家投入时间去学习,它们主要出现在第3章里面,其他章节中的某些内容(如第36条)也同样可以归为这一类,我们可以在日常工作中运用这些内容来解决问题。大家应该花时间去学习这些内容,并且要逐步实践它们。这或许意味着我们要放弃自己所熟悉的调试工具,而去使用一些学习曲线较为陡峭但是功能上更加先进的调试工具,那些工具虽然一开始学起来比较困难,可是从长远来看,却能够帮助你成为调试方面的专家。
调试的思路。当我们遇到困难时,可以根据这些思路来找寻合适的技巧。这些内容不一定每天都会用到,但是当你遇到一个琢磨不透的问题时,它可以帮助你节省一整天(或者说至少几小时)的时间。比如,如果你不清楚自己所写的C和C 代码为什么无法编译,那么第50条或许能给你一些启发。大家应该快速浏览这些内容,使自己意识到它们可以在某些场合派上用场,等到真正需要使用它们的时候,再去详细研究。
本书对软件开发的其他方面所起的作用本书里的所有条目都是针对故障的诊断与调试而写的,不过其中有很多建议同样可以用来缩减代码中的bug数量,并且可以使你在遇到这样的bug时能够更为迅速地将其修复。严谨的调试技术与优秀的软件开发方式之间能够形成良性的循环,因此,书中的建议对于你当前或者将来要面对的软件设计、软件构建以及软件管理工作,是可以起到帮助作用的。
设计软件的时候,应该遵循下列建议:
使用与其角色相称的高级机制(参见第47条和第66条)。
提供调试模式(参见第6条和第40条)。
提供对系统操作进行监控与记录的机制(参见第27条、第41条和第56条)。
提供一个选项,使得开发者可以用Unix命令行工具来编写与组件有关的脚本(参见第22条)。
把内部的错误暴露出来,使其表现为软件故障,而不要将其隐藏起来,使其成为软件中的不稳定因素(参见第55条)。
提供一种方式,使得开发者能够在软件发生故障之后获得内存转储(memory dump)信息(参见第35条和第60条)。
从数量和范围方面,尽量缩减软件在执行时的不确定因素(参见第63条)。
构建软件的时候,应该遵循下列建议:
征求同事的意见(参见第39条)。
为你所编写的每个例程创建单元测试(参见第42条)。
用断言来验证自己所做的假设是否成立,以及代码的功能是否正确(参见第43条)。
尽量把代码写得易于维护,也就是要写出易读、稳定且便于分析和修改的代码(参见第46条和第48条)。
在构建程序时避免不确定的因素(参见第52条)。
在对软件的开发及运作进行管理时,应该遵循下列建议(无论是要管理一个团队,还是只管理自己的流程):
用适当的事务追踪系统,把遇到的问题记录下来(参见第1条)。
对各种有待处理的事务进行分类,并排定其优先次序(参见第8条)。
把对软件所做的修改适当地记录在修订管理系统中,并且对该系统进行较好的维护(参见第26条)。
渐进地部署软件,使得我们可以在新旧版本之间进行对比(参见第5条)。
尽量采用各种不同的工具来开发,并试着把程序部署在各种环境中(参见第7条)。
经常对工具与程序库进行更新(参见第14条)。
如果使用了第三方的程序库,那么可以考虑购买该程序库的源代码(参见第15条);考虑购买一些较为完善的工具来锁定那些不太容易找到的错误(参见第51条、第59条、第62条、第64条及第65条)。
寻找专门的工具来调试硬件接口及嵌入式系统(参见第16条)。
使得开发者能够远程调试软件(参见第18条)。
对于消耗资源较多的故障诊断任务来说,要留出足够的CPU及磁盘资源(参见第19条)。
鼓励开发者之间通过代码评审及编程指导等手段进行协作(参见第39条)。
鼓励大家进行测试驱动开发(参见第42条)。
在构建软件的时候,要做性能分析、静态分析以及动态分析(参见第57条、第51条及第59条),并且要打造一套迅速而高效的构建流程与测试流程(参见第53条及第11条)。
对书中术语的说明本书所说的fault(错误)一词,遵循ISO-24765—2010(Systems and software engi-neering——Vocabulary)标准,它的意思是:“计算机程序里面某个不正确的步骤、流程或数据定义。”这也称为defect(缺陷)。在日常工作中,我们把这叫做bug。与之类似,本书所用的failure(故障)一词,也遵循ISO-24765—2010标准,它指的是:“因系统或系统组件未能在规定限制之下执行所需功能而引发的事件。”故障可以表现为程序崩溃、程序冻结或是程序的结果有误。故障一词强调的是程序运行的后果,而错误一词强调的则是我们所遇到或使用的某个程序本身有问题。不过有的时候,大家也会用错误及缺陷这两个词来指代故障,ISO标准也承认了这一点。笔者在本书中会按照上述定义来区分这几个词,然而在语境比较明确的情况下,我通常也会用问题(problem)一词来指代错误(如“代码有问题”)或故障(如“可以重现的问题”),这样写能够使本书读起来更加流畅,而不至于变成一份法律文件。
Unix操作系统的shell、程序库以及工具,目前都可以运行在各种各样的平台上。笔者采用Unix一词来指代遵从Unix原则及API的任何一种系统,包括Apple的Mac OS X、各种GNU/Linux发行版(如Arch Linux、CentOS、Debian、Fedora、openSUSE、Red Hat Enterprise Linux、Slackware及Ubuntu)、直接从Unix继承而来的系统(如AIX、HP-UX及Solaris)、各种BSD衍生系统(如FreeBSD、OpenBSD及NetBSD),以及运行在Windows系统上的Cygwin。
本书中所列出的C 、Java或Python代码,针对的也是较新的编程语言版本,不过笔者会避开那些奇怪的或是刚刚推出的特性。
书里面会出现“你的代码”和“你的软件”这两种说法,它们指的是你正在调试的代码以及正在开发的软件。这两种说法听起来比较简洁,而且也暗含了一种对代码所有权的宣示,这对于软件开发人员来说是十分重要的。
笔者所说的例程(routine)一词,是指可供调用的代码单元,如成员函数、方法、函数、过程以及子例程等。
Visual Studio及Windows指的是Microsoft公司的相关产品。
修订控制系统(revision control system)及版本控制系统(version control system),是指像Git这样能够对软件配置进行管理的工具。
排版约定Unix命令行选项使用–this这样的形式,与该选项等价的单字母选项使用-t这样的形式。Windows工具中的对应选项,使用/this这样的形式。
按键采用Shift-F11这样的形式。
文件路径采用/etc/motd这样的形式。
菜单操作采用Debug-New Breakpoint-Break at Function这样的形式。
为了缩短篇幅,笔者会省略C 代码中的std::限定符及std名称空间。
描述GUI(图形用户界面)工具时,笔者所说的功能针对的
评论
还没有评论。