怎样高效编写可维护代码?
原文:How to make your code self-documenting?
译文:怎么让代码自我文档化?
译者:dwqs
在代码中找到一个放错地方而且没实用的凝视是不是非常有趣呢?
怎么样才干做到写非常少的凝视但仍能让代码易于理解呢?
一个基本的方式就是让代码自我文档化。当代码自我文档化的时候,就不须要凝视去它的作用或者目的,而且也能使代码变得很easy维护。
在这篇文章中,我将提供一些让你的代码自我文档化的方式。以下就是三种使得代码自文档化的基本方法:
- 命名:利用名字来解释变量、函数等的目的。
- 封装函数:将一些特定功能的代码封装成一个函数以明白目的。
- 引入变量:将表达式插入至专用变量。
这可能看上去非常easy。但在实际操作过程中会让人认为有点棘手。首先你得明确哪些地方有问题以及哪些地方适用这些方法。
此外,除了上述三种,另一些应用比較广泛的方式:
- 类和模块接口:将类和模块中的函数暴露出来,让代码更加清晰。
- 代码分组:用组来区分不同的代码片段。
接下来我们将通过实例,详细讲一讲怎样在实际应用中运用上述5个方法。
一、命名
首先,看几个怎样利用命名时代码变得清晰和自我文档化的样例。
1、重命名函数
给函数命名不是非常难,你能够遵守下面规则:
- 避免使用含糊的字眼,比如“handle”或“manage”——handleLinks、manageObjects。
- 使用主动动词——cutGrass、sendFile。以表示函数主动运行。
- 指定返回值类型——getMagicBullet、READFILE。
强类型的语言也能够用类型标识符来表明函数的返回值类型。
2、重命名变量
- 指定单位——假设里面有数值參数。那能够加上其单位。比如,用widthPx来代替width以指定宽度的单位是像素。
- 不要使用快捷键——a和b都不能作为參数名。
二、函数封装
接下来,看几个怎样将代码封装成函数的样例。封装函数的一个优点就是避免代码反复,或者说改进代码结构。
1、将代码封装成函数
这是最主要的:将代码封装成函数以明白其目的。猜猜以下这行代码是干什么的:
var width = (value - 0.5) * 16;
好像不是非常清楚,当然有凝视就一清二楚了,可是我们全然能够封装成函数以实现自文档化……
var width = emToPixels(value); function emToPixels(ems) { return (ems - 0.5) * 16; }
唯一改变的是计算过程被转移到了一个函数里。该函数名明白地表达了它要做什么,这样一来就不必写凝视了。并且,假设有须要后面还能够直接调用此函数,一举两得。降低了反复劳动。
2、用函数取代条件表达式
If语句假设包括多个运算对象,不写凝视的话理解起来就比較难。
if(!el.offsetWidth || !el.offsetHeight) { }
知道上面这代码的目的不?
function isVisible(el) { return el.offsetWidth && el.offsetHeight; } if(!isVisible(el)) { }
三、引入变量
最后再讲讲怎样引入变量。
相较于上面两个方法,这个可能没那么实用,可是不管怎样,知道比不知道好。
1、用变量取代表达式
看看上面的样例
if(!el.offsetWidth || !el.offsetHeight) { }
这下不封装成函数,用引入变量取代
var isVisible = el.offsetWidth && el.offsetHeight; if(!isVisible) { }
2、用变量取代方程式
我们也能够用来清楚说明复杂程式:
return a * b + (c / d);
用变量来取代
var divisor = c / d; var multiplier = a * b; return multiplier + divisor;
四、类和模块接口
类和模块的接口——也是面向公共的方法和属性——有点像说明怎样使用的文档。
看以下的样例:
class Box { public function setState(state) { this.state = state; } public function getState() { return this.state; } }
这个类也能够包括其它代码。我特意举这个样例是想说明公共接口怎样自文档化。
你能说出这个类是怎样被调用的吗?非常显然,这并不明显。
这两个函数都应该换个合理的名字以表述它们的目的。
但即便做到这一点,我们还是不怎么清楚怎样使用。然后就须要阅读很多其它的代码或者翻阅文档。
可是假设我们这样改一下呢……
class Box { public function open() { this.state = open; } public function close() { this.state = closed; } public function isOpen() { return this.state == open; } }
是不是清晰多了?注意:我们仅仅是修改了公共接口,其内部表达与原先的this.state状态同样。
五、代码分组
用组来区分不同的代码片段也是自文档化的一种形式。比如,像这篇文章中说的那样。我们应该尽可能将变量定义在靠近使用它的地方,而且尽可能将变量分门别类。
这也能够用来指定不同代码组之间的关系。这样更加方便其它人知道他们还须要了解哪些代码组。
看以下的样例:
var foo = 1;
blah()
xyz();
bar(foo);
baz(1337);
quux(foo);
与以下的比較:
var foo = 1;
bar(foo);
quux(foo);
blah()
xyz();
baz(1337);
将foo的全部使用组合放在一起。一眼望去就能知道各种关系。可是有时候我们不得不在中间调用一些其它函数。所以假设能够那就尽量使用代码分组,假设不能够,那就不要强求。
六、其他建议
- 不要使用奇怪的标记,以下两个是等价的
imTricky && doMagic();
if(imTricky) { doMagic(); }
显然后者比較好。语法技巧并没有带来什么优点。
- 命名常量:假设代码里面有一些特殊值,那最好给它们命名。var PURPOSE_OF_LIFE = 42;
- 制定规则:最好遵循同样的命名规则。
这样阅读的人就能在參考其它代码的基础上正确推測出各种事物的含义。