编程中,调试几乎是必不可少的,一劳永逸、一次完成预想功能而完全不出bug的情况凤毛麟角,出现bug→调试→再出现bug→再调试……基本是软件工程中的常态。可以说,软件调试是每个coder的必修课,而《软件调试修炼之道》便是一本调试教科书,考虑到前两次大作业中出现的各种bug,我有必要系统地学习debug的一些思想和技巧,因此本周我阅读了这本书的Part 1:问题的核心。这一部分由五章组成:山重水复疑无路,重现问题,诊断,修复缺陷,反思。以下我将分别浅谈我的阅读感想。

  1、概览调试:流程、问题和原则

  第一章名为“山重水复疑无路”,颇为扑朔迷离的命名,内容却很明晰:介绍软件调试,简单概述调试的流程、原则和遇到的问题,为后四章详细铺叙起头。其中给我感触比较深的是关于调试的意义与价值的介绍。在我和身边同学的一贯认知中,调试就是为自己的bug买单,算是编程中最令人烦躁、耗费大量时间而收获寥寥、时常引起心态伴随程序一起崩的工作,我每次点下“ctrl+F7/F5”和设置断点查看结果,都伴随着难以名状的期待:但愿不要出bug。而本书中认为,真正的调试并非简单的修复缺陷,而是要发现问题、解决问题、提高代码质量并确保问题不再发生。为调试所花的时间往往比敲代码更有意义和价值。回想过去的编程经历,确实如此。我已记不清大整数加减乘除的实现算法,但却能轻易想起当初调试越界问题、数组移位进位问题的教训;编写数独程序的生成算法和QT界面代码我也印象不深了,但对QT信号传递、部件命名的debug过程还历历在目。短期而言,调试确实让我们抓耳挠腮、耗费心力却只解决了某个细节问题;但从长远来看,每一次调试都让我们交足了学费、痛定思痛,不再跌入同一个坑。同时,调试往往比重写更有效率。个人作业中的词频搜索里,由于一个判断逻辑的错误,我的输出与示例偏差很大,一度想要换算法重写。但经过调试,最终只改了一个if中的判断条件,便符合了需求,省下了不少功夫。

  原则方面,按照约定俗成的经验,我们基本上每次调试只解决一个问题,同时避免影响其他部分的正常工作,以免顾此失彼、焦头烂额。

  2、调试核心:重现、诊断、修复和反思

  重现,即发现问题,之后才能谈解决。在简单程序的debug中,往往不需要重现,因为bug就堂堂正正地摆在眼前耀武扬威;但软件发布后的调试中,很多情况下是基于用户反馈的缺陷,往往需要重现问题,来发现问题所在、寻求解决方案。书中介绍了朴素的控制变量法和玄学的推测法等。在结对编程中,我们的dll发布后交由UI组测试,与软件交付用户的流程比较相近,调试流程也基本相同。好在好心的UI组们基本都把可能的bug给我们列举出来,我们只需要用推测法简单尝试就能发现问题,也有一些问题是显而易见的,例如泛用性、便利性等。总而言之,发现问题是解决问题的第一步,重现问题,才能做到有的放矢。

  诊断,即发现问题后提出假设、进行实验,直到找到症结所在。这种思想方法在我们过往的断点debug中经常使用。当结果不符合预期时,我们会先通过断点确定问题出现的区域,再通过实验逐步找到问题语句,完成诊断。更科学地说,可以通过“插桩法”“二分法”等方式“排雷”,这些也算是老生常谈了。需要注意的是,诊断有时会造成“陷阱”,即看错症结、治标不治本。词频统计作业中,我曾在调试中改错条件,使得输出结果里原本错误的词汇统计变得正确了,但词组统计依旧错误,后来发现修改处不正确,只是生硬地打上了补丁。可见找准问题所在、外科手术式精准定位和修改后仔细筛查,是非常重要的。

  修复,是调试的最终阶段,也是最可能出问题的阶段。这是因为有些问题的症结根深蒂固,甚至修复代价大得让人难以接受。在日常生活中其实不乏这样的例子,比如某程序的核心算法存在致命缺陷,只能重构;比如某校BBS论坛的实现中纯用C语言完成,甚至连数据库都没有,落后时代十几年而基本无法有效维护、更新,修复的工作量基本和推倒重建的工作量差不多。这时,“掩盖真相”的手法应运而生:不管根本原因出在哪里,只要用一些操作来让输出结果正确就可以。这样的方法确实有一些效果,也能避免付出过大的修复代价,但高风险、留隐患的弊端也是显而易见。惭愧的是,我在结对编程中也使用了这样“掩盖真相”的手法。由于某些我debug良久而想不通的原因,生成算式中乘方(^)后跟的数字会超过我设置的限制范围,还会带上括号,最终我选择通过暴力筛选手段筛掉不合要求的式子,并通过不断超量生成式子、选出合适的式子的操作来使输出的式子都正确。客观来说,这样的做法实质上并没有解决核心问题,但实际操作中确实卓有成效,算是没有办法的办法。现实中的修复当然还是要力求解决根本问题,但有时也不得不为效率和资源做出妥协,个人而言,我真诚地期望不再使用“表面补丁”修复程序,而是更负责地进行重构。

  反思,就是吸取经验教训了。每一次调试都是为我们犯下的错误买单,包括数据结构选择的不合理、算法的缺陷、逻辑错误和键入失误等。常言道,吃一堑长一智,每次调试都是总结错误、吸取教训的宝贵经历。

  总而言之,调试的核心流程近似一个瀑布模型,各流程间又不断迭代。在调试中解决问题、提升程序的完整性和可靠性,正是软件调试修炼之道。

《软件调试修炼之道》Part 1(CH1~5)读书笔记 PB16110698 第八周(~4.26)的更多相关文章

  1. 《代码整洁之道》ch1~ch4读书笔记 PB16110698 (~3.8 第一周)

    <代码整洁之道>ch1~ch4读书笔记  <clean code>正如其书名所言,是一本关于整洁代码规范的“教科书”.作者在书中通过实例阐述了整洁代码带来的种种利处以及混乱代码 ...

  2. 《移山之道》第十一章:两人合作 读书笔记 PB16110698 第六周(~4.15)

     本周在考虑阅读材料时,我翻阅了<移山之道>,正好看到这一章:两人合作,心想:正好,我们正值结对作业的紧要关头,书中两人合作的宝贵经验和教诲应当对我们有很大帮助.于是,我开始一边在ddl苦 ...

  3. 《代码整洁之道》ch5~ch9读书笔记 PB16110698(~3.15) 第二周

    <代码整洁之道>ch5~ch9读书笔记 本周我阅读了本书的第5~9章节,进一步了解整洁代码需要注意的几个方面:格式.对象与数据结构.错误处理.边界测试.单元测试和类的规范.以下我将分别记录 ...

  4. 《Linux内核设计与实现》读书笔记(十八)- 内核调试

    内核调试的难点在于它不能像用户态程序调试那样打断点,随时暂停查看各个变量的状态. 也不能像用户态程序那样崩溃后迅速的重启,恢复初始状态. 用户态程序和内核交互,用户态程序的各种状态,错误等可以由内核来 ...

  5. 软件开发-MSF方法(《构建之法》读书笔记2)

    MSF-微软解决方案框架,是一套大型系统开发指南,它描述了如何用组队模型.过程模型和应用模型来开发Client/Server结构的应用程序,是在微软的工具和技术的基础上建立并开发分布式企业系统应用的参 ...

  6. <《巴菲特之道 (第三版)》>读书笔记

    以便宜的价格买入长期绩优的股票 他把对公司的投资看做是拥有公司的一部分股权,看重的是公司的长期经济价值 别人越是草率,我们越要加倍慎重 如果你发现自己已经在陷阱中,最重要的是想办法让自己不要再往下陷 ...

  7. 《单元测试之道Java版》的读书笔记

    总览 第2章 首个单元测试 第3章 使用JUnit编写测试 3.1 构建单元测试 3.2 JUnit的各种断言 3.3 JUnit框架 4. 测试什么? 5.CORRECT(正确的)边界条件 6.使用 ...

  8. <读书笔记>软件调试之道 :从大局看调试-理想的调试环境

    声明:本文档的内容主要来源于书籍<软件调试修炼之道>作者Paul Butcher,属于读书笔记.欢迎转载! ---------------------------------------- ...

  9. <读书笔记>软件调试之道 :从大局看调试-零容忍策略

    声明:本文档的内容主要来源于书籍<软件调试修炼之道>作者Paul Butcher,属于读书笔记.欢迎转载! ---------------------------------------- ...

随机推荐

  1. PAT_A1117#Eddington Number

    Source: PAT A1117 Eddington Number (25 分) Description: British astronomer Eddington liked to ride a ...

  2. LeetCode刷题笔记-DP算法-取数问题

    题目描述 (除数博弈论)爱丽丝和鲍勃一起玩游戏,他们轮流行动.爱丽丝先手开局. 最初,黑板上有一个数字 N .在每个玩家的回合,玩家需要执行以下操作: 选出任一 x,满足 0 < x < ...

  3. Codeforces 1189B Number Circle

    题目链接:http://codeforces.com/problemset/problem/1189/B AC代码: #include<bits/stdc++.h> using names ...

  4. 力扣算法题—111.Minimum Depth of Binary Tree

      Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the sh ...

  5. Linux环境变量永久设置方法(zsh)

    1.之前一直使用:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./home/46005/cuda-9.0/lib64/来设置cuda库路径变量 -----临时的,当 ...

  6. Linux特殊位SUID、SGID、SBIT

    Linux特殊位SUID.SGID.SBIT 前言 Linux中的文件权限一般有x.w.r,在某个情况下有需要用到s.t,即特殊位. 进程运行时能够访问哪些资源或文件,不取决于进程文件的属主属组,而是 ...

  7. python项目部署

    WSGI简介 Web框架和Wen服务器之间需要进行通信,如果在设计时它们之间无法相互匹配,那么对框架的选择就会限制对Web服务器的选择,这显然是不合理的.这时候需要设计一套双方都遵守的接口.WSGI是 ...

  8. 找到最大或者最小的N个元素

    heapq模块中的两个函数nlargest()和nsmallest() import heapq nums = [1,5,6,458,6,787,5,45,6] print(heapq.nlarges ...

  9. github合并分支到master

    (1)切换到master分支 git checkout master (2) 将backup分支的代合并到master git merge backup (3) 查看状态 git status (4) ...

  10. Gulp执行预处理

    1. 在项目中安装 gulp-sass插件来编译Sass npm install gulp-sass --save-dev 2. 在gulpfile.js中编写 var gulp = require( ...