调试是确定错误根本原因并纠正此错误的过程。对很多程序员来说,调试是程序设计中最为困难的部分。

1、 调试概述

  • 调试在软件质量中所扮演的角色

    同测试一样,调试本身并不是改进代码质量的方法,而是诊断代码缺陷的一种方法。开发高质量软件产品的最佳途径是精确描述需求,完善设计,并使用高质量的代码编写规范,调试只是迫不得已时采用的手段。

  • 调试效率的巨大差异

    并不是每个人都知道怎么调试。不同的开发人员通过调试发现缺陷的速度区别很大。

  • 让你有所收获的缺陷

    • 理解你正在编写的程序
    • 明确你犯了哪种类型的错误
    • 从代码阅读者的角度分析代码质量
    • 审视自己解决问题的方法
    • 审视自己修正缺陷的方法
  • 效率低下的调试方法

    • 调试魔鬼指南

      • 凭猜测找出缺陷
      • 不要把时间浪费在理解问题上
      • 用最唾手可得的方式修正错误
    • 迷信式调试

      即使某个错误初看似乎并不归咎于你,但出于自身利益,最好还是假设它的产生同你有关。

2、寻找缺陷

  • 科学的调试方法

    • 通过可重复的实验收集数据
    • 根据相关数据的统计构造一个假说
    • 设计一个实验来证明或反证这个假说
    • 证明或反证一个假说
    • 根据需要重复上述步骤
  • 寻找缺陷的有效方法

    • 将错误状态稳定下来
    • 确定错误的来源

      • 收集产生缺陷的相关数据
      • 分析收集的数据,并构造对缺陷的假设
      • 确定怎样去证实或证伪这个假设
      • 按照上一条确定的方法对假设做出最终结论
    • 修补缺陷
    • 对所修补的地方进行测试
    • 查找是否有类似错误
  • 寻找缺陷的小建议

    • 构造假设时,考虑所有的可用数据
    • 提炼产生错误的测试用例
    • 在自己的单元测试族中测试代码
    • 利用可用的工具
    • 采用多种不同的方法重现错误
    • 用更多的数据生成更多的假设
    • 利用否定性测试用例的结果
    • 对可能的假设尝试头脑风暴
    • 在桌上放一个记事本,把需要尝试的事情逐条列出
    • 缩小嫌疑代码的范围
    • 对之前出现过的缺陷的类和子程序保持警惕
    • 检查最近修改过的代码
    • 扩展嫌疑代码的范围
    • 增量式集成
    • 检查常见缺陷
    • 同其他人讨论问题
    • 抛开问题,休息一下
  • 蛮力调试

    • 对崩溃代码的设计和编码进行彻底检查
    • 抛弃有问题的代码,从头开始设计和编程
    • 抛弃整个程序,从头开始设计和编程
    • 编译代码时生成全部的调试信息
    • 在最为苛刻的警告级别中编译代码,不放过任何一个细微的编译器警告
    • 全面执行单元测试,并将新代码隔离起来单独测试
    • 开发自动化测试工具,通宵达旦的对代码进行测试
    • 在调试器中手动遍历一个大循环,直到发现错误条件
    • 在代码中加入打印、显示和其他日志记录语句
    • 用另一个不同的编译器来编译代码
    • 在另一个不同的环境里编译和运行程序
    • 在代码运行部正确的时候,使用能够产生警告信息的特殊库或者执行环境来链接和运行代码
    • 复制最终用户的完整系统配置信息
    • 将新的代码分小段进行集成,对每段集成的代码进行完整的测试
  • 消除语法错误

    • 不要过分信任编译器信息中的行号
    • 不要迷信编译器的信息
    • 不要轻信编译器的第二条信息
    • 分而治之
    • 找出没有配对的注释或者引号

3、修正缺陷

减少出错几率的建议:

  • 动手之前先理解问题
  • 理解程序本身,而不仅仅是问题
  • 验证对错误的分析
  • 放松一下
  • 保留最初的源代码
  • 治本而不是治标
  • 修改代码时一定要有恰当的理由
  • 一次只做一个改动
  • 检查自己的改动
  • 增加能暴露问题的单元测试
  • 搜索类似的缺陷

4、调试中的心理因素

  • 心理趋向如何导致调试盲目

人总期望一个新的现象类似于他们见到过的某种现象。你指看到你希望看到的东西,因而忽视了他们之间的差别。当发现错误的时候,程序员对于需要检查的程序部分的选择会不同。高效的程序员们能够在调试代码时,对无关紧要的部分视而不见。

  • 心理距离在调试中的作用

心理距离可以定义为区分两事物的难易程度。在调试时,要警惕哪些没有足够心理距离的相似变量名或者子程序名。而在编写代码的时候,应该为变量或子程序选择差别较大的字,从而避免此类问题发生。

5、调试工具

  • 源代码比较工具
  • 编译器的警告消息

    • 将编译器的警告级别设置为最高级,尽可能不放过任何一个警告,然后修正编译器报告的全部错误
    • 用对付错误的态度来处理警告
    • 在项目组范围内使用统一的编译设置
  • 增强的语法检查和逻辑检查
  • 执行性能剖测器
  • 测试框架/脚手架
  • 调试器

更多有关《代码大全 2》的读书笔记,请关注 :
http://tabalt.net/blog/code-complete-2-reading-notes/

本文链接:http://tabalt.net/blog/cc2-debugging/,转载请注明。