The Art of Readable Code

简介

短小精悍的编程建议,常读常新。

第一章:代码应当易于理解

1.代码的写法应当使别人理解它所需的时间最小化
理解的要求就是别人看完你的代码后,能够动手改动或优化你的代码。
写代码的时候应该以能够像自然语言一样易于理解为目标。

2.代码并不是行数越少就越容易理解

第一部分:表面层次的改进

第二章:把信息装到名字里

1.选择专业的词
举例:
int size() => int Height()/NumNodes()/MemoryBytes()
简单的使用size不能直接反应出返回值使什么的size。
如果可以的话选用更具体、更符合情景的专业词汇对于可读性有较大的帮助。

2.避免使用tmp和retval这样泛泛的变量/函数名
除非有十分好的理由,比如常见的swap函数中的tmp。

3.用具体的名字代替抽象的名字
书中有一个插图很好的阐释了这点:动物和危险动物

4.给变量带上重要的细节
比如添加单位等,可以参考微软的“匈牙利表示法”

第三章:不要误解的名字

1.推荐用min和max来表示(包含)极限
2.推荐用first和last来表示包含的范围
3.推荐用begin和end来表示包含/排除范围
4.要小心用户对特定词的期望。例如,用户会期望get()
或者size()是轻量的方法。

这章讲的内容感觉需要有较多的实践应验才能区分哪些名字会产生误解
所以这里仅列出了书中强调的几条经验

第四章:审美

1.三条大原则:
使用一致的布局,让读者很快就习惯这种风格 让相似的代码看上去相似
*把相关的代码行分组,形成代码块

2.如果代码中存在大量的重复代码,或许该考虑添加一个函数了。
一个合适的小函数能有效提高代码的视觉美感

3.在需要时使用列对齐

4.选一个有意思的顺序,始终一致地使用它
常见的顺序:重要性、字母序

5.把声明按块组织起来
这点对于类或者较大的结构体尤为重要

6.个人风格与一致性
一个人的代码风格如果能够保持一致,这比“正确”的风格更重要。
最好的学习代码风格的资料就是Linux源码!
推荐一些我了解的一些代码风格的资料:
Gem5 Coding Style
Google C++ Style Guide

第五章:该写什么样的注释

1.关键思想:注释的目的时尽量帮助读者了解得和作者一样多

2.最好的注释就是代码本身,不要为了注释而注释
自解释的代码比任何的注释都要好,好代码>坏代码+好注释

3.不要给不好的名字加注释—应该把名字改好

4.为代码的瑕疵写注释
如果阅读过Linux源码会发现里面有很多’TODO’的注释,这点很值得学习
很多时候第一版的代码是想尽快的完成某个功能,在实现过程中想到的一些可能
的优化如果暂时不便实现,加上一个’TODO’的注释或许是一个不错的选择。
书中列出了一些流行的标记类的注释。

5.给常量加注释
常量的值往往不是重点,而为什么常量被设置为这个值才是重点。
添加合适的注释解释这些信息,对代码的可读性有较大的帮助。

6.站在读者的角度
这点比较有意思,这类注释更像是对于某个问题的解答。
对于一些意料之中的问题,添加注释进行回答能节省许多不必要的时间

7.公布可能的陷阱
这点的出发点与第6条类似

8.全局观的注释:用注释来总结代码块,使读者不致迷失在细节中。
注释的目的是帮助读者更好更快的理解你的代码,
给出一些总结性的注释能够省去读者很多的时间。
对于一个较复杂的函数,如果能一针见血的指出函数完成的功能、输入和输出,
读者就可以根据需要要选择性的阅读你的代码。这点对于复杂的大项目尤为重要。

第6章:写出言简意赅的注释

这章的内容看下章首的插图就能一目了然,就不多解释了。

第二部分:简化循环和逻辑

用更加清晰的方式来实现代码的逻辑至关重要,
对于一段时候后重新来阅读或调试这段代码尤其重要。

第7章:把控制流变得易读

关键思想:把条件、循环以及其他对控制流的改变做的越自然越好。
运用一种方式使读者不用停下来重读你的代码。

1.条件语句中参数的顺序
代码同样需要符合人阅读的习惯
指导原则:
比较的左侧:“被问询的”表达式,它的值更倾向于不断变化 比较的右侧:用来做比较的表达式,它的值更倾向于常量

2.if/else的顺序
首先处理正逻辑而不是负逻辑的情况,例如:用if(debug)而不用if(!debug) 先处理掉简单的情况。这种方式可能还会使得if和else在屏幕之内都可见,这很好
*先处理有趣或者是可以的情况

3.代码行数越少不一定越好,更好的度量方法是最小化人们理解它所需要的时间

4.尽量减少代码的嵌套层数
嵌套的层次越多,之后代码的优化和修改就越复杂。
书中提到了一些有效的方法避免过多的嵌套,如提前从函数中返回或使用break

第8章:拆分超长的表达式

关键思想:把你的超长表达式拆分成更容易理解的小块
人脑能同时处理的信息量有限,就好比巨星乌贼一次吃多了就容易伤到大脑

1.拆分表达式最简单的方法就是引入一个额外的变量,让它来表示一个小一点
的子表达式。这个额外的变量有时叫做“解释变量”,因为它可以帮助解释
子表达式的含义。

2.使用德摩根定理对复杂的逻辑表达式简化
如果使用此方法简化了逻辑表达式,那么最好添加相应的注释。
因为转换过后的表达式理解起来没那么直接。

3.找到更优雅的方式
一个复杂的逻辑,如果考虑它的反面或许就没有那么复杂了。
书中的例子就是两个区间的重叠的判断,值得一读

第9章:变量与可读性

1.减少没有价值的临时变量
至于判断是否存在价值,这需要常年的积累。

2.减少控制流变量
还是那个理由:人脑同时能够处理的事情有限

3.缩小变量的作用域
缩小了变量的作用域,同样减少了读代码时需要记在脑海中的信息
同时还避免了变量冲突

4.只写一次的变量更好
基于的思想:操作一个变量的地方越多,越难确定它的当前值

第三部分:重新组织代码

第10章:抽取不相关的子问题

核心思想:把一般代码和项目专有的代码分开
书中指出 :大部分的代码都是一般代码。通过建立一个大组库和辅助函数来
解决一般问题,剩下的只是让你的程序与众不同的核心部分。

1.创建大量通用代码
如果字符串需要以某种格式输出,而这种格式经常被用到,那么你该考虑
用一个类似format_pretty()的函数专门负责将字符串转换成特定格式。

第11章:一次只做一件事

关键思想:应该把代码组织得一次只做一件事

下面是用于使代码“一次只做一件事”所用到的流程:
列出代码所做的所有“任务”。这里的任务没有很严格的定义—它可以很小 尽量把这些任务拆分到不同的函数中,或者至少是代码中不同的段落中

第12章:把想法变成代码

1.清晰地描述逻辑
把一个想法用“自然语言”解释是一个很有价值的能力
代码不仅仅是写给机器执行的,更多的时候是写给人读的,所以代码的逻辑
能够像“自然语言”那般的描述出来,对于代码的理解有莫大的帮助

2.了解库函数很有帮助和必要
了解库函数避免重复造轮子,不仅能够提高效率,而且库函数的使用很大程度
的保障了正确性。
当然要想完全了解库函数每个函数的具体用法,将是一个十分巨大的工程。
我们能够做的就是常常翻翻主要库的文档,在实现某项功能的时候能够想到
库函数中好像有类似的实现就可以了

3.在动手写代码之前,先尝试用自然语言描述解决方法是一个很好的习惯

第13章:少写代码

1.在项目开始时写的代码只有很少的代码留到最终版本中

2.写代码前,需要反复考虑和质疑的你需求
很多时候你认为需要的功能,到最后都没有实现的必要

3.用最合适的方式实现你的需求
书中有一个关于缓存的例子。如果数据的重复访问只处在一行,那么没有必要
实现一个复杂的LRU策略。

4.使用UNIX工具而非编写代码
这点我的体会最深。跑实验的时候处理数据,如果每次都要写代码的话,
就不用跑实验了。使用一些常用的文本处理命令能有效地提高效率,
比如cat、awk、cut等。

第四部分:精选话题

这部分主要是一些关于测试和一个小功能的具体实现举例,具体还是看书比较好。

总结

本书很多的内容都需要通过大量的实践才能透彻的领悟,常读常新。
本书的可读性也很强,书中又有许多有趣的插图,
能够让你一下子就体会到整个一章的精髓。