欧内斯特.海明威(Erners Hemingway) :
严肃是写作必备的两大要素之一。另一个,很不辛,是天分。
我们编写代码,是要表达一套清晰的指令,它不仅仅面向电脑,也面向修改、拓展和维护这些指令的人。
在软件产品的生命周期内,代码将不断地被修改、拓展和维护。所以文档化代码是一件有益的工作。
一、如何代码文档化
编写大量关于代码的文档
有时可以见到由设计规范、实现说明、维护指南和风格指南支持的软件系统,这种做法会导致如下问题:
(a).除了编写程序外,要耗费大量时间去编写文档和阅读文档;
(b).所有文档必须随代码更改而及时更新,否则会导致危险的错误和产生误导信息;
(c).大量文档的管理也是一大问题;
(d).由于信息没有放在代码旁,一些重要信息容易被忽略。使用详细的代码注释
这是一种可选方案,但容易写出一堆毫无创造性的逐条注释。最理想的方案:写自文档化的代码
我们要相信:唯一能完整并正确地描述代码的文档是代码本身。
我们应当尽可能地编写可读性高的代码,这种代码本身易于理解,甚至不需要任何外部文档或注释加以说明。如下面这段代码:
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;
}
这段代码没有注释,但我们很容易读懂它。
二、编写"自文档化"代码的技能:
-
使用好的样式,编写简单的代码。
(a).程序流程分明。错误情况不会扰乱程序正常执行流程;
(b).避免使用过多的嵌套语句;
(c).谨慎地优化代码,让它清晰地表达基础算法。 -
选择有意义的名称
具体见《读《编程匠艺—编写卓越的代码》:命名》 -
用多个简单的函数代替复杂的函数
(a).一个函数,一种操作;
(b).减少任何出人意料的副作用,它们会要求额外文档的;
(c).保持简短,短小的函数更易于理解。 -
选择描述性的类型。
(a).定义永远不变的值为常值变量(C/C++使用const);
(b).定义非负变量为无符号类型;
(c).使用枚举描述一组相关值;
(d).选择适当类型。C/C++中,将值的大小放入size_t变量,将指针放入ptrdiff_t变量。 -
命名常量
对于常量字符串和数字,不要直接在代码中使用。如if (counter == 72)
这样的代码会让人无法理解,神奇数字72
是什么,if
的目的是什么呢,我们不知道;但如果写成
const size_t bananas_per_cake = 72;
....
if (count == bananas_per_cake)
{
//做香蕉蛋糕
}
就清晰很多。容易明白数字72
代表每个蛋糕需要的香蕉数目,而且如果需要改变数字72
,只需做一个改动即可。
-
强调重要的代码
(a).在类中按一定数序进行声明:用户需要的公共信息在前,对用户不重要的私有的实现细节放在后面;
(b).尽可能隐藏所有不重要信息。C++中,使用pimpl idiom实现类的实现细节; -
尽可能通过语言结构将对象分组。
C++/C#中通过命名空间分组;Java中使用包分组。 -
提供文件头
在文件顶部放置一个注释块,简述文件内容、所属项目及版权声明* -
恰当地处理错误
(a). 在最恰当的上下文中处理错误;
(b).不要返回无意义的错误信息。 -
编写有意义的注释
先考虑优化代码(如换一个名字或新增一个下属函数)。只有在你无法以任何其他方式来提高代码清晰度的情况下,再添加恰当的注释。
三、实用的自文档化方法
《编程风格的元素》中Kernighan和Plaugher:
不要对糟糕的代码进行文档化——重写这些代码。
A. 文学编程
著名计算机科学家Donald Knuth在他的1992年出版的《文学编程》提出了一种极端的自文档化代码技巧——文学编程,并在书中详细描述了这种编程方法。
B.文档化工具
利用工具通过分离特殊格式的注释块,从源代码生成文档。
可以文档化你编写的任何代码:类、类型、函数、参数、标志、变量等,还能方便地获取大量信息:
- 指定版本信息
- 记录创建日期
- 交叉引用信息
- 将旧代码标记为过时
- 为快速引用提供简短的对照表
- 描述每个函数的参数
流行的代码文档化工具有:
- Java的Javadoc
- C#的NDoc
- 适用于多种编程语言的Doxygen
一些有用的经验:
- 对于每个公共可见的对象,都编写一两句描述,不要冒险写太多文字。
- 如果变量或参数用途不明显,请简要说明;如果它们的名字表达的很清楚,则不用添加描述
- 如果函数的一些参数用于输入,另一些用于输出,需明确说明
- 不要文档化任何一个函数的前置和后置条件
四、总结
埃德温·施罗斯伯格(Edwin Schlossberg):
写作的技巧就是创建一个上下文语境,别人在其中思考
代码本身就是一种交流媒介,考虑那些需要维护代码的程序员们的需求,努力写出清晰的代码——用最少最恰当的注释/文档,用"自文档化"的代码。
内容相关
Pimpl idiom
Pimopl是C++开发中经常使用的一种惯用法,其原理主要是将对定义的依赖转换为对声明的依赖,通过前向声明,达到接口与实现的分离的效果,并将编译时文件间的依赖降到最低,从而大大缩短程序编译的时间。简单点说,就是将一个类分割为两个类,一个提供接口,一个负责实现,既能最小化编译依赖,又能接口与实现分离。Pimpl的实现方式有两种,第一种是让实现类成为接口类的一个私有指针成员变量;另一种实现方式则是通过继承的方式实现:让接口类成为抽象基类,这个基类包含一个返回该类指针的静态方法,该方法通过实现类的构造函数实现,实现类继承自这个抽象基类,并实现基类描述的接口。『示例可查看PIMPL IDIOM & FAST PIMPL』
写作与编程
关于写作技巧的提高,有一个简单的原则:读的书越多,写得就越好。用批判的眼光阅读著名作者的作品,可以使你学会如何分辨好坏,还能从中学到新的技巧和习惯用法。类似的,如果你阅读大量优秀的代码,那么你也会成为一位更出色的程序员。你会在编写代码时不自觉地运用好的技巧,一旦写出糟糕的代码,你会立马警觉,甚至浑身不自在。