跳到主要内容

剔除bug的设计

bug 的主要来源是什么?​

  • 来源: 系统各组成部分的开发者都会做出一些假设, 而这些假设之间的不匹配, 是大多数致命和难以察觉的 bug 的主要来源;
  • 主要对策: 获取概念完整性--它使产品更易用, 同时使开发更容易、bug 更不容易产生;
  • 支撑手段: 详尽体系结构设计, 细致的功能定义、详细的规格说明、规范化的功能描述说明;
  • 引证(Vyssotsky): 关键的工作是产品定义, 许许多多的失败完全源于那些产品未精确定义的地方;

为什么规格说明要提交测试小组?​

  • 时机: 在编写任何代码之前;
  • 目的: 详细检查说明的完整性和明确性;
  • 为什么不能靠开发人员自查(Vyssotsky): "他们不会告诉你他们不懂; 相反, 他们乐于自己摸索出解决问题和澄清疑惑的办法";
  • 推论: 需要一个独立角色专门挑规格说明的漏洞, 这与第 6 章的独立产品测试小组是同一逻辑;

自顶向下的设计如何避免 bug?​

  • 来源: Wirth 1971 年的论文把很多优秀编程人员使用的设计流程形式化;
  • 过程: 把设计看成一系列精化步骤--先勾画粗略的任务定义和解决方案, 再检查结果与期望的差距, 然后在更细的步骤中分解;
  • 双向精化: 任务定义的精化变成算法的精化, 还可能伴随数据表达方式的精化;
  • 独立性: 识别出模块后, 对模块的进一步细化可以与其他工作独立进行; 模块大小决定程序的适用性和可变化程度;
  • 表达层次: 每一步尽可能使用较高级别的表达方法表现概念、隐藏细节, 除非必须进一步细化;
  • 四个好处:
    • 清晰的结构和表达方式更容易精确描述需求和模块功能;
    • 模块分割和模块独立性避免了系统级 bug;
    • 细节隐藏使结构缺陷更容易识别;
    • 每个精化步骤的层次上都可以测试, 所以测试可以尽早开始, 并放在合适的级别;
  • 允许回退: 遇到意想不到的问题时可以推翻顶层设计重新开始; 自顶向下方法减少了"试图挽救基础很差的设计、不断打补丁"的企图;

结构化编程的核心主张是什么,有哪些争议?​

  • 理论依据: Bohm 和 Jacopini 证明只需少量控制结构即可表达任意程序;
  • 主张(Dijkstra): 控制结构仅包含循环(如 DO WHILE)和条件(IF...THEN...ELSE), 不加限制的 GO TO 分支跳转会产生导致自身逻辑错误的结构;
  • 反面意见: 一些附加控制结构非常有效, 如多路分支(CASE/SWITCH)、异常跳转; 完全避免 GO TO 显得有些教条和吹毛求疵;
  • 真正的核心: 把系统的结构作为控制结构来考虑, 而不是独立的跳转语句;
  • 作者评价: 这种思考方法是程序设计发展史上向前迈出的一大步;

细节隐藏与变更的关系?​

  • 自顶向下设计的副作用: 模块分割和细节隐藏让结构缺陷更易识别, 也让变更更局部化;
  • 与信息隐藏的关系: 20 年后作者承认 Parnas 的信息隐藏"是唯一提高软件设计水平的途径", 它面对变更时更健壮;
  • 权衡: Mills 的开放技术让程序员理解接口另一侧的详细语义, 接口隐藏会导致系统 bug; Parnas 的技术面对变更更健壮, 更适合"为变更设计";