Udacity调试课笔记之调试者的工作方式
Udacity调试课之调试者的工作方式
Udacity的课程确实嗖嗖嗖地就蒙过去了。所以,不总结下不行了。
调试课第一单元How debuggers work
总的来说,本单元就是在讲科学方法(Scientific Method),以及如何在调试过程中使用科学方法。而编程练习则是构建一个交互式调试器。
课程内容:
1、调试的基础知识。(应该是基本概念)
2、科学方法
3、清晰调试
4、用Python构建Python的交互式调试器
3和4是我自己凑上去的,这样更加清楚、明确。
一、调试的基础知识
回顾自己的调试经历,是否在调试时有种调到海枯石烂、天荒地老,山无棱、天地合,乃敢调出来的感觉,是不是想着和bug同归于尽了?
来看一份魔鬼调试指南说明书,看看你满足其中几条。
魔鬼调试指南:
1、处处print。想看谁就看谁,想哪儿看就哪儿看。
2、猜测式巧合编程。哥是无敌幸运星,bug一向随意改改就搞定,呃,偶尔改到面目全非也没搞定。
3、从不备份。什么?难道你没听说过破釜沉舟、刻舟求剑、背水一战?给自己退路的人,怎么能勇往直前!
4、理解程序很烦。为什么要理解程序的目的意图?看注释、代码很晕的好不好。
5、神来之笔。兵来将挡,水来土掩。大不了,哥用一堆if,也要跟你卯上了!脚痛医脚,头痛砍头,这么浅显的道理,难道你不懂吗?
第5条的神来之笔何意?举例说明。假设,你写了个程序或者就是一个函数,比如是求平方根的函数……当你输入4的时候,你知道的,返回值肯定是2。就假设,你的函数有问题,于是返回了1.2 或是直接整个程序就挂掉了。试了半天,没解决这个问题,于是,你一怒之下,在函数开头来了句神来之笔:
if x == 4 then return 2;
上面这个例子过于极端,只是我也想不出来靠谱的例子。神来之笔的实际含义就是针对症状而不是问题来进行修复,只要症状解决、不再出现(出错),也就不再管bug是否还在。所谓的治标不治本。希望大家能理解。
看完魔鬼调试指南,让我们速速回到人间,太上老君急急如律令!看看人间调试指南是什么样的。
人间调试指南:
1、解决问题。解决bug,而不只是bug引起的症状。针对魔鬼法则5
2、理解程序。理解程序的意图,分析输入和期望输出。针对魔鬼法则4
3、版本控制、备份。针对魔鬼法则3
4、使用系统的调试方法。针对魔鬼法则1和2
坚持使用人间调试指南,就是你变得职业的必经之路。西天取经要上路,一走就是十万里。不强迫自己养成这个习惯,如何称得上专业人士?
就像《中国电影人物访谈》(是叫这个吧)之王晶篇里,王晶从编剧的角度来说,什么叫专业。专业就是,在你刚刚失恋之后,让你写一个爱情喜剧,男女主角幸福生活在一起的剧本。你也要高质量、不受情绪影响地写出来,这就叫专业。所以他说,靠直觉、灵感的都不叫专业。虽然他现在拍的喜剧电影也是越来越不专业了。
要去取经,万里长征第一步,让我想到广告。在我们磨刀霍霍向bug时,我们要先做到以下几点:
1、理解问题。理解程序出了什么问题。
2、理解程序目的。程序原本是打算做什么,结果应该是什么。
3、预测下如何解决问题,而不是症状。也就是提出个解决问题的可能方案。
第3点将是下一部分,科学方法的前提。
最后来点概念了。一堆英语名词解释,让我们尽情地晕吧。无所谓。
失败(failure)——用户在程序外看到的错误。
错误(error)——偏离了正确,不再正确的都是错误。晕。
缺陷(defect)——代码中的error,将有效的状态变成错误的状态,进而可能引起程序的失败(failure)。
Fault——也就是缺陷(defect),不过它还用于描述数据data的问题。
Bug——缺陷的最著名的说法,等价。指bug本不属于代码的一部分,自己爬进来的。但Zeller认为bug就是程序员写出来的,所以他更偏好defect这个词。
Infection(不清楚有没有对应的术语)——程序状态中的错误,由带缺陷的语句引入。
上面几个名词间还有一些比较绕的关系,什么不是每个什么都是什么什么的。
再提一个后续单元经常用到的概念。
Cause effect chain,我只能想到翻译成因果链。因果链其实就是
defect (代码中的缺陷) -- infection (运行时的缺陷) -- progate(扩散) -- failure (失败)。
而调试的目的就是,
发现因果链,并打破它(从源头解决)。
下一部分就是科学方法。
二、科学方法
科学方法其实一个流程图就列完了。如图(呃,真是偷懒了,直接从视频中截了图片过来,以后争取制下图):
用段流程化的文字来描述就是:
1、根据程序的代码、运行情况、失败情况、观察结果等等因素,提出一个假说(hypothesis),也就是上一部分,准备工作中的第3条,可能的bug解决方案。转步骤2.
2、预测结果,记录,并进行实验,再记录观察结果,比对。转步骤3。
3、如果比对结果一致,表示实验结果支持提出的假说,可以对假说进行改进,再转步骤2(图片中是转步骤1);否则表示假说不符,不正确,拒绝掉,转步骤1,提出新假说。
直到假说不能再改进,且所有实验(所有测试)结果都符合,则转入步骤4.
4、假说能解释并预测实验(测试)结果,所以变成一个学说,调试里就是诊断结果(诊断报告)。OVER。
这个过程很简单,看过一遍后,多数人都能理解并记住。难点就在于应用上。视频里,Zeller教授说,对于经验丰富的程序员来说,如果能在5分钟内解决问题,确实可以不用这么系统或者叫死板地使用科学方法。
Zeller教授假设看视频的人是编程高手,而我不能这么假设,所以我的观点有所不同。对于新手、生手来说,需要强制地使用这么一个方法、过程(一万小时理论),不断地练习,这样才会有进步,才会真正地向高手转变。唯一或者说少数的例外,只在于当看到程序出错,甚至运行程序的那一刹那,就能想到bug所在,这种情况下自然是直接修改代码即可。但只要想法不正确,或10秒内没想到问题所在,1分钟内无法解决bug,就要强制地使用科学方法。当成长为专家、高手之后,科学方法已经成为习惯,自然能掌握好使用它的时机。
三、清晰调试
清晰调试(Explicit Debugging,自译不标准)的内容主要有两点,一是记录,二是描述。
所谓记录,即及时记录重要调试信息。如程序输入,预期结果,实际结果。尤其在使用科学方法时,提出的假说、假想的解决方案同样重要。也许习惯了记在脑中,可工作中干扰过多,记忆的时长也有限,一旦遗忘,大侠又要重新来过。只要下班之前,将信息记录在案,第二天上班时,就可以以清醒的大脑再战江湖,何乐而不为?
而描述、阐述从表面上看,是向某人(甚至某只泰迪熊、玩具鸭)描述自己遇到的问题,实际上也是在整理思路、理清脉络,使之更加结构化,于是可能在描述bug时,突然霍然开朗,手舞足蹈地离开,留下满头雾水的同伴(所以才要换作一只泰迪熊、玩具鸭)。
第一单元教学部分笔记至此结束。后面还有练习部分,主要是Python构建Python的交互式调试器,利用到几个重要的函数。自己重心暂时在理论学习上,所以实践部分没有总结。顺便可惜一下就是,Python交互式调试器的实现因为Python有个很好的API而轻而易举,但C语言、Pascal语言的调试器就需要额外的知识了。更不用说,面对的主要语言是一门自制语言,根本没有调试器。我能自己为之编写出调试器,自然是大功一件……
我去,CSDN博客增加缩进难道这么麻烦?这是博客……不是代码文件。