读《编程匠艺—编写卓越的代码》:编写“自文档化”代码

欧内斯特.海明威(Erners Hemingway) :
严肃是写作必备的两大要素之一。另一个,很不辛,是天分

我们编写代码,是要表达一套清晰的指令,它不仅仅面向电脑,也面向修改、拓展和维护这些指令的人。

在软件产品的生命周期内,代码将不断地被修改、拓展和维护。所以文档化代码是一件有益的工作。

一、如何代码文档化

  1. 编写大量关于代码的文档
    有时可以见到由设计规范、实现说明、维护指南和风格指南支持的软件系统,这种做法会导致如下问题:
    (a).除了编写程序外,要耗费大量时间去编写文档和阅读文档;
    (b).所有文档必须随代码更改而及时更新,否则会导致危险的错误和产生误导信息;
    (c).大量文档的管理也是一大问题;
    (d).由于信息没有放在代码旁,一些重要信息容易被忽略。

  2. 使用详细的代码注释
    这是一种可选方案,但容易写出一堆毫无创造性的逐条注释。

  3. 最理想的方案:写自文档化的代码
    我们要相信:唯一能完整并正确地描述代码的文档是代码本身
    我们应当尽可能地编写可读性高的代码,这种代码本身易于理解,甚至不需要任何外部文档或注释加以说明。如下面这段代码:

int fibonacci(int position)
{
      if (position < 2)
      {
          return 1;
      }
      int previousButOne = 1;
      int previous       = 1;
      int answer         = 2;

      for (int i = 2; i < position; i++)
      {
                previousButOne = previous;
                previous       = answer;
                answer         = previousButOne + previous;
       } 
       return answer;
}

这段代码没有注释,但我们很容易读懂它。

二、编写"自文档化"代码的技能:

  1. 使用好的样式,编写简单的代码
    (a).程序流程分明。错误情况不会扰乱程序正常执行流程;
    (b).避免使用过多的嵌套语句;
    (c).谨慎地优化代码,让它清晰地表达基础算法。
  2. 选择有意义的名称
    具体见《读《编程匠艺—编写卓越的代码》:命名》
  3. 用多个简单的函数代替复杂的函数
    (a).一个函数,一种操作;
    (b).减少任何出人意料的副作用,它们会要求额外文档的;
    (c).保持简短,短小的函数更易于理解。
  4. 选择描述性的类型
    (a).定义永远不变的值为常值变量(C/C++使用const);
    (b).定义非负变量为无符号类型;
    (c).使用枚举描述一组相关值;
    (d).选择适当类型。C/C++中,将值的大小放入size_t变量,将指针放入ptrdiff_t变量。
  5. 命名常量
    对于常量字符串和数字,不要直接在代码中使用。如if (counter == 72)这样的代码会让人无法理解,神奇数字72是什么,if的目的是什么呢,我们不知道;但如果写成
const size_t bananas_per_cake = 72;
....
if (count == bananas_per_cake)
{
      //做香蕉蛋糕
}

就清晰很多。容易明白数字72代表每个蛋糕需要的香蕉数目,而且如果需要改变数字72,只需做一个改动即可。

  1. 强调重要的代码
    (a).在类中按一定数序进行声明:用户需要的公共信息在前,对用户不重要的私有的实现细节放在后面;
    (b).尽可能隐藏所有不重要信息。C++中,使用pimpl idiom实现类的实现细节;
  2. 尽可能通过语言结构将对象分组
    C++/C#中通过命名空间分组;Java中使用包分组。
  3. 提供文件头
    在文件顶部放置一个注释块,简述文件内容、所属项目及版权声明*
  4. 恰当地处理错误
    (a). 在最恰当的上下文中处理错误;
    (b).不要返回无意义的错误信息。
  5. 编写有意义的注释
    先考虑优化代码(如换一个名字或新增一个下属函数)。只有在你无法以任何其他方式来提高代码清晰度的情况下,再添加恰当的注释。

三、实用的自文档化方法

《编程风格的元素》中Kernighan和Plaugher:
不要对糟糕的代码进行文档化——重写这些代码。

A. 文学编程

著名计算机科学家Donald Knuth在他的1992年出版的《文学编程》提出了一种极端的自文档化代码技巧——文学编程,并在书中详细描述了这种编程方法。

B.文档化工具

利用工具通过分离特殊格式的注释块,从源代码生成文档。

可以文档化你编写的任何代码:类、类型、函数、参数、标志、变量等,还能方便地获取大量信息:

  • 指定版本信息
  • 记录创建日期
  • 交叉引用信息
  • 将旧代码标记为过时
  • 为快速引用提供简短的对照表
  • 描述每个函数的参数

流行的代码文档化工具有:

  • Java的Javadoc
  • C#的NDoc
  • 适用于多种编程语言的Doxygen

一些有用的经验:

  • 对于每个公共可见的对象,都编写一两句描述,不要冒险写太多文字。
  • 如果变量或参数用途不明显,请简要说明;如果它们的名字表达的很清楚,则不用添加描述
  • 如果函数的一些参数用于输入,另一些用于输出,需明确说明
  • 不要文档化任何一个函数的前置和后置条件

四、总结

埃德温·施罗斯伯格(Edwin Schlossberg):
写作的技巧就是创建一个上下文语境,别人在其中思考

代码本身就是一种交流媒介,考虑那些需要维护代码的程序员们的需求,努力写出清晰的代码——用最少最恰当的注释/文档,用"自文档化"的代码。

内容相关

Pimpl idiom
Pimopl是C++开发中经常使用的一种惯用法,其原理主要是将对定义的依赖转换为对声明的依赖,通过前向声明,达到接口与实现的分离的效果,并将编译时文件间的依赖降到最低,从而大大缩短程序编译的时间。简单点说,就是将一个类分割为两个类,一个提供接口,一个负责实现,既能最小化编译依赖,又能接口与实现分离。Pimpl的实现方式有两种,第一种是让实现类成为接口类的一个私有指针成员变量;另一种实现方式则是通过继承的方式实现:让接口类成为抽象基类,这个基类包含一个返回该类指针的静态方法,该方法通过实现类的构造函数实现,实现类继承自这个抽象基类,并实现基类描述的接口。『示例可查看PIMPL IDIOM & FAST PIMPL』

写作与编程
关于写作技巧的提高,有一个简单的原则:读的书越多,写得就越好。用批判的眼光阅读著名作者的作品,可以使你学会如何分辨好坏,还能从中学到新的技巧和习惯用法。类似的,如果你阅读大量优秀的代码,那么你也会成为一位更出色的程序员。你会在编写代码时不自觉地运用好的技巧,一旦写出糟糕的代码,你会立马警觉,甚至浑身不自在。

你可能感兴趣的:(读《编程匠艺—编写卓越的代码》:编写“自文档化”代码)