编程精粹—— Microsoft 编写优质无错 C 程序秘诀 04:对程序进行逐步跟踪

本文主要是介绍编程精粹—— Microsoft 编写优质无错 C 程序秘诀 04:对程序进行逐步跟踪,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这是一本老书,作者 Steve Maguire 在微软工作期间写了这本书,英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字,英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》,这本书主要讨论如何编写健壮、高质量的代码。作者在书中分享了许多实际编程的技巧和经验,旨在帮助开发人员避免常见的编程错误,提高代码的可靠性和可维护性。


不记录,等于没读。本文记录书中第四章内容:对程序进行逐步跟踪。


前两章我们讲到了 断言为子系统设防 这两种自动化检查方法,这两种检查措施都很有价值。我们也说过,不要等待错误发生。要“挨门挨户”的搜查错误:在程序中加上能够积极地寻找这种问题的调试代码。
这里隐含着一个条件,你必须知道哪里可能会发生错误,也就是说:事先,你得知道错误“长什么样”。如果你不知道错误是什么,就抓不到这个错误。比如你只在门窗上安装了报警器,那么当小偷从地下室的开口进入,就不会引起警报。
保证家中物品不被偷走的可靠办法是:在小偷有可能光顾的期间内呆在家里。防止错误进入程序的办法也是这样,在 最有可能出现错误 的时候,密切关注。因此,找到错误的最佳方法是使用调试器逐步执行所有新代码。通过逐步执行每条指令,关注数据流,可以快速发现表达式和算法中的问题。专注于数据而不是指令,可以从另一个角度来审视代码。逐步调试代码虽然花时间,但远没有大多数程序员想象的那么耗时。

那么,什么时候是 最有可能出现错误的时候?
答案是:在编写或修改程序的时候,最可能出现错误,我们要认识到这一点的重要性。编写无错代码的最好办法是在编译时对其进行详尽的测试。

我们在第一章中介绍了 黑箱 测试。测试者给程序提供大量的输入,然后检查输出,如果测试者认为相应的输出没有问题,那么则认为程序没有问题。

黑箱测试的缺陷在于,除了提供输入和检查输出之外,测试者再没有别的方法对代码进行测试。给一些输入,得到了正确的输出,并不能保证代码是正确的。就像你问一些问题,倾听对方回答,并不能确定对方是不是疯子,因为你不知道对方脑袋里在想些什么。

上面的这些限制对程序员来说都不是什么难事。程序员可以在代码中设置断点,一步一步跟踪代码的运行,观察输入变为输出的过程。程序员测试程序最好的办法是对代码进行逐条跟踪,对中间的结果进行认真的查看。

不要等到出了错误再对程序进行逐条地跟踪

  • 对正常处理程序逐条跟踪

  • 对错误处理部分逐条跟踪

  • 对程序中每一条可能的路径逐条跟踪(明显的路径:ifswitch,其它路径:&&||?:

习惯于对代码进行逐条跟踪会产生一个有趣的现象,即他们很快就会学会编写较小的容易测试的函数,因为对大函数进行逐条地跟踪非常痛苦。

对代码进行逐条跟踪的真正作用是:可以使我们观察到数据在函数汇中的流动

如果单步执行仍不能得到执行的细节,那么对于关键部分的代码要进行汇编指令级的逐条跟踪

小结

  • 代码不会自己生出错误,错误是程序员的产物,编写新代码或者修改现有代码都可能产生错误。如果想发现代码中的错误,最好的方法是逐条跟踪代码。
  • 逐条跟踪代码并不会花费太多时间,与返工带来的影响相比,这点时间划算的很。
  • 一定要对每一条代码路径进行逐条的跟踪,尤其是错误处理部分。&&||?: 运算符,它们每个都有两条代码路径需要测试。
  • 当需要汇编级别的逐条跟踪时,不要回避。

题外话

本书第一稿出版于 1993 年,当时软件工程领域还没有 敏捷开发测试驱动开发 等概念(这些概念大范围被认可是在 2000 年左右)。作者写这本书的时候遵循一个理念,那就是只介绍那些并不广为人知,没有被广泛实践,也没有被广泛使用的概念和开发哲学。那个时候作者已经认识到测试的重要性,提倡编写较小的容易测试的函数。在当今 (2024 年) 来看,这是再平常不过的事情,甚至,对于“防止错误进入程序”,我们也有了更号的方法,那就是 测试驱动编程 。我在之前的博文《C 嵌入式系统设计模式 01:软件开发概述》中描述过自己对测试驱动开发的见解,现摘录如下:

开发无缺陷软件的最新技术是一种称为 测试驱动开发 (TDD) 的敏捷实践。

无缺陷的软件 (defect-free software)表示该软件没有任何错误、缺陷或问题,能够按照预期的功能和需求正常运行。

“开发无缺陷的软件?这怎么可能!”换做以前的我,不假思索地就会如此断言。但那时的我,从没有想过,我给出的这个结论,依据是什么。事实上,我没有依据,我连脑子都没动过一下,就草率地下了这样的判断。

而现在,我开始反思这个问题,一方面是因为我的思维方式发生了转变,不再轻易地给出片面的结论;另一方面,是因为我尝试了测试驱动开发。尽管我依然认为开发完全无缺陷的软件是一个难以企及的目标,但测试驱动开发确实让我看到了这一目标的可能性。它让我对我的软件质量越来越有信心。

在尝试测试驱动开发的早期,最难以理解、最难以坚持的可能是被称为 Bob Martin 的测试驱动 3 条原则:

  1. 不允许编写任何产品代码,除非它可以让失败的单元测试通过。
  2. 不允许编写任何足以导致失败的更多的单元测试,编译失败也算失败。
  3. 不允许编写任何足以让单元测试通过的更多的产品代码
  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

首先,你需要先编写单元测试,这就是为什么叫做测试驱动的原因之一。但是根据规则 2,你不能写太多的单元测试,一旦单元测试代码无法编译或者断言失败,就必须编写产品代码。但是根据规则 3,你只能编写恰好使单元测试编译通过或者断言通过的产品代码,而不能再多!

当我年轻时,我曾尝试测试驱动编程,先后尝试过两次,都因为第 2 和第 3 条原则而放弃,我觉得它很愚蠢!如果你没有尝试过测试驱动开发,也许无法体会到我当时的感受。没有关系,我只是想分享一下我曾经的态度和后来的变化。

随着年龄的增长,我的思维方式发生了转变,我收起了排斥和轻视的态度,放下成见,严格遵守测试驱动原则来编写一个程序。然后,我被测试驱动开发迷住了。

我开始认识到,那些我曾经认为愚蠢的规则,实际上并不愚蠢,而是构建稳健软件必不可少的基础,坚持这样的原则,能确保我的代码在全面且细致的测试用例中得到验证,换句话说,能产生彻底测试过的产品代码。

彻底测试,是每一个软件开发者的理想目标,只有达到这一条件,我们才有可能触及编写无缺陷软件的可能。很多时候,我们都在竭尽全力追求彻底测试,但受限于大脑的逻辑和记忆能力,总是会遗漏某些测试路径。然而,遵守测试驱动开发的 3 条原则,可以帮助我们系统化地进行测试,确保每一个细节都得到了验证。只是遵守 3 条原则,就能实现如此的效果,这真是太划算了。


题外话 2

如果你对测试驱动感兴趣,想详细了解,推荐阅读《测试驱动的嵌入式 C 语言开发》。这本书的原作者和译者,给予他们再多的赞美都不为过。






每一份打赏,都是对创作者劳动的肯定与回报。
千金难买知识,但可以买好多奶粉

这篇关于编程精粹—— Microsoft 编写优质无错 C 程序秘诀 04:对程序进行逐步跟踪的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1072440

相关文章

python编写朋克风格的天气查询程序

《python编写朋克风格的天气查询程序》这篇文章主要为大家详细介绍了一个基于Python的桌面应用程序,使用了tkinter库来创建图形用户界面并通过requests库调用Open-MeteoAPI... 目录工具介绍工具使用说明python脚本内容如何运行脚本工具介绍这个天气查询工具是一个基于 Pyt

Linux使用scp进行远程目录文件复制的详细步骤和示例

《Linux使用scp进行远程目录文件复制的详细步骤和示例》在Linux系统中,scp(安全复制协议)是一个使用SSH(安全外壳协议)进行文件和目录安全传输的命令,它允许在远程主机之间复制文件和目录,... 目录1. 什么是scp?2. 语法3. 示例示例 1: 复制本地目录到远程主机示例 2: 复制远程主

Ubuntu设置程序开机自启动的操作步骤

《Ubuntu设置程序开机自启动的操作步骤》在部署程序到边缘端时,我们总希望可以通电即启动我们写好的程序,本篇博客用以记录如何在ubuntu开机执行某条命令或者某个可执行程序,需要的朋友可以参考下... 目录1、概述2、图形界面设置3、设置为Systemd服务1、概述测试环境:Ubuntu22.04 带图

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

Python程序打包exe,单文件和多文件方式

《Python程序打包exe,单文件和多文件方式》:本文主要介绍Python程序打包exe,单文件和多文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python 脚本打成exe文件安装Pyinstaller准备一个ico图标打包方式一(适用于文件较少的程

windows系统上如何进行maven安装和配置方式

《windows系统上如何进行maven安装和配置方式》:本文主要介绍windows系统上如何进行maven安装和配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录1. Maven 简介2. maven的下载与安装2.1 下载 Maven2.2 Maven安装2.

C/C++的OpenCV 进行图像梯度提取的几种实现

《C/C++的OpenCV进行图像梯度提取的几种实现》本文主要介绍了C/C++的OpenCV进行图像梯度提取的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录预www.chinasem.cn备知识1. 图像加载与预处理2. Sobel 算子计算 X 和 Y

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL

Python程序的文件头部声明小结

《Python程序的文件头部声明小结》在Python文件的顶部声明编码通常是必须的,尤其是在处理非ASCII字符时,下面就来介绍一下两种头部文件声明,具有一定的参考价值,感兴趣的可以了解一下... 目录一、# coding=utf-8二、#!/usr/bin/env python三、运行Python程序四、

Go语言中使用JWT进行身份验证的几种方式

《Go语言中使用JWT进行身份验证的几种方式》本文主要介绍了Go语言中使用JWT进行身份验证的几种方式,包括dgrijalva/jwt-go、golang-jwt/jwt、lestrrat-go/jw... 目录简介1. github.com/dgrijalva/jwt-go安装:使用示例:解释:2. gi