编写可读代码的艺术(此篇会持续更新,欢迎大家前来指正)
发布于 4 年前 作者 Huyaguang 2517 次浏览 来自 分享

一、代码应当易于理解 大多数程序员依靠直觉和灵感来决定如何编程。我们都知道这样的代码: for (Node* node = list->head; node != NULL; node = node->next) Print(node->data); 比下面的代码好: Node* node = list->head; if (node == NULL) return;

while (node->next != NULL) {
    Print(node->data);
    node = node->next;
}
if (node != NULL) Print(node->data);

(尽管两个例子的行为完全一样)

但很多时候这个选择会更艰难。例如,这段代码: return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent); 它比下面这段要好一些还是差一些? if (exponent >= 0) { return mantissa * (1 << exponent) } else { return mantissa / (1 << -exponent); } 很显然,第一个例子虽然是一行代码,但是没有下边这个例子清晰可读。

可读性的关键思想是:代码的写法应当使别人理解它所需的时间最小化。 代码好不好不是说代码量越小越好,也不是说使用的方法越高级越好,而是别人理解它所使用的时间越短越好。

如果你写了一些不容易理解的代码,这样别人就会很费力的才能看明白,当然,等过一段时间之后,你自己也会很费解。

二、把信息装到名字中 这个话题很重要,因为会影响到你代码库中的每一行代码。尽管每个改变可能看上去都很小,聚集在一起造成代码库巨大的改进。如果你的代码有很棒的名字、写的很好的注释,并且整洁地使用了空白符,你的代码会变得易读得多。

无论是命名变量、函数还是类,都可以使用很多相同的原则。我们喜欢把名字当做一条小小的注释。尽管空间不算很大,但选择一个号名字可以让他承载很多信息

本章的思想:把信息装入名字中。 本章的6个专题:

  1. 选择专业的词。
  2. 避免泛泛的名字(或者说要知道什么时候使用它)。
  3. 用具体的名字代替抽象的名字。
  4. 使用前缀或者后缀给名字附带更多信息。
  5. 决定名字的长度。
  6. 利用名字的格式来表达含义。

选择专业的词 要避免使用“空洞”的词。 比如在二叉树中的一个例子: class BinatyTree { int Size(); }; 这个 Size() 什么意思呢?这是个疑问,因为它没有承载很多信息。更专业的词可以是 Height()、NumNodes() 或者 MemoryBytes()。 再比如stop这个词,这个词的意思是停止,但是准确来说是暂停?还是终止?其实更贴切的词是kill、pause、shutdown等。

找到更有表现力的词 单词send对应的词有:deliver、dispatch、announce、distribute、route …… 单词find对应的词有:search、extract、locate、recover …… 单词start对应的词有:launch、create、begin、open …… 单词make对应的词有:create、set up、build、generate、compose、add、new ……

循环迭代器 像i、j、iter和it等名字常用作索引和迭代器。 但有时会有比这些更贴切的迭代器命名。例如: for (int i = 0; i < clubs.size(); i++) { for (int j = 0; j < clubs.members.size(); j++) { for (int k = 0; k < users.size(); k++) { if (clubs[i].members[k] == users[j]) cout << “user[” << j << “] is in club[” << i << “]” << endl; } } } 在if条件语句中,members[]和user[]用了错误的索引。这样的缺陷很难被发现,因为一行代码单独来看似乎没有问题: if (clubs[i].members[k] == users[j]) 在这种情况下,使用更精确的名字可能会有帮助。 如果把i、j、k对应改为:club_i、member_i、user_i,或者简单点:ci、mi、ui。这样就变成了这样 if (clubs[ci].members[ui] == users[mi]) // 这样错误就一目了然了

为名字附带更多信息 一个箱子里装了一只危险的动物,封上口,箱子上写着“动物”两个字,很多人可能会好奇打开看看是什么动物,如果打开则他自己就会受伤。如果这个箱子上再加上“危险”这两个字,就不会有这样悲剧发生了。 为名字附带更多信息在单位的值中使用是最明显的,例如JavaScript中度量一个网页的加载时间 var start = (new Date()).getTime(); 如果这个start变量更改为start_ms是不是更明显呢?

总结

  1. 使用专业的单词,例如,不用Get,而使用Fetch或者Download可能会更好,这由上下文决定
  2. 避免空泛的名字
  3. 使用具体的名字来更细致地描述事物,ServerCanStart()这个名字就比CanListenOnPort更不清楚。
  4. 给变量名带上重要的细节,例如值为毫秒的变量后面加上_ms,或者在还需要转义的,未处理的变量前面加上raw_。
  5. 为作用域大的名字采用更长的名字,不要用让人费解的一个或两个字母的名字来命名在几屏之间都看见的变量。对于只存在于几行之间的变量用短一点的名字更好。
  6. 有目的地使用大小写、下划线

来自《编写可读代码的艺术》 大家有什么好的想法,欢迎指正

回到顶部