最近读了《编写可读代码的艺术》这本书,感觉收获良多。如果早点了解的话,可能以前就不会犯那么多新手错误了,不过话说回来,理论总是要配合实践才能内化成自己的东西,而且书中的内容适合反复温习,一定常读常新。

整本书的核心都在于一个原则:代码应当易于理解。所以作者在开篇就提出了可读性的概念:

代码的写法应当使别人理解它所需要的时间最小化。

其中可读性很容易与代码长度混淆,因为代码本身的精简达到一定程度,就难免涉及到晦涩的逻辑压缩和语言用法,而这恰恰是和易读性相悖的。另外代码是写给人看的,这里指的不一定是别人,在实际工作中更有可能是若干天后的自己,所以保证可读性不仅利人,同样利己。 以此为中心,可以发散到编码过程中的很多方面,比如基础的变量命名、代码注释、函数定义以及开发后期的文档维护、解耦重构等等。

One of the hard things

There are only two hard things in Computer Science: cache invalidation and naming things. – Phil Karlton

这句名言一句道破天机,万物皆从命名始,起名字的能力实在是太重要了。不论是变量常量,还是方法类名,一旦确定名称,代码的整体风格就开始受到影响,并且一直持续下去。

记得刚写代码的时候,并没有觉得合适的变量名称很重要,后来时间长了,慢慢开始琢磨起什么名字好,然后发现换来换去都不合适,为此绞尽脑汁,耗费的时间甚至比开发都长。现在熟练了不少,虽然有时还要再思索几下,但是命名已经比以前清晰很多了。反观周围的同事们,越是高手,在 naming 上也越得心应手,可能这也是编码能力发展的自然规律吧。

书里介绍的各种技巧,基本都围绕在信息量和准确性两点。前者可以保证名称是足够有意义的,同时也在检验变量存在的必要性;而后者能够减少代码中重复或混淆的定义,甚至提供了借助命名 debug 的可能性。

另外让我印象深刻的是,英文单词量有时候也会成为命名能力的瓶颈。比如对于常用的 make 来说,作为动词来描述一个操作可能并不足够清晰,更好的选择可以是 create/generate/setup/compose 等,但是英文不熟练或者词汇量有限的话,就难以在合适的时候想起来,或者要去专门查询才行。不知道未来会不会普及中文编程,不过那样难度仍在,只是从英语课切换成语文课了。

It’s not just about code

在代码里加注释是一件很有争议的事情,因此作者也提到了很重要的一点,要明确什么时候是不需要注释的。好的代码如同优秀的文章,自成一体,但这不影响添加一些额外的说明和解释可以提高阅读理解的效率。

广义上想,注释其实也算是另一种形式的文档。一行代码的注释,对象换成函数方法、模块文件或整个工程的话,就会演变成文字片段、README 甚至是单独的 DOCBOOK。而这些对于不需要了解逻辑细节的人来说,是比代码本身更高效的入口。

回想自己在工作日常中,写文档的时间并不比开发少,但两者其实并不冲突,归根到底都是要把任务描述清楚,一个写给人,另外一个给机器。代码写得清晰,文档维护也会非常轻松。

而在其他的场景中,比如开源的工具库,使用者对文档的关注度会更高,一方面会从文档的质量上评判整个项目,另一方面在使用中大部分情况也是阅读文档,而非源代码。

Be wise, not smart

每种编程语言都少不了流程控制的部分,再加上特有的语法糖,想写出精巧的代码并不是难事。 Oneliner 非但不难,还很容易有成就感,尤其是成功地把冗长的逻辑压缩在一行空间内。

但是这种做法的后果可能是灾难性的。抛开可读性原则不谈,这样的写法在新增 feature 和 debug 时会带来额外的成本,尤其是后者。因为排查错误的时候往往需要快速的定位和修复,而碰上复杂的条件分支和循环语句时,一是逻辑拆解浪费时间,再者想做改动也可能很困难,因为代码已经变得像个精 致的花瓶,一碰就碎了。

不得不说没有实际的经历,很难体会到这里面的道理,看似矛盾,实则展现了一个 coder 的成长过程:一开始专注于逻辑堆叠,后期追求奇技淫巧的写法,最终回归质朴的实现方式。

One thing at a time

观察周围的同事写代码时,有不少人都会念念有词地对着屏幕说话,一开始觉得奇怪,后来发现和小黄鸭调试法不谋而合。念叨的内容不外乎代码要做什么事、犯了什么错之类,而在此过程中,隐藏的问题往往会自动浮现。这也是书里提到的把想法变成代码,关键在于是否能把程序要做的事情用自然语言解释清楚。

现在写一个函数,脑中就会自动展现各个子任务,像参数和返回值的设计、内部逻辑的解耦、与其他函数的依赖关系等等。所以对于书中提到的一次只做一件事,虽然精华,但自己写得时间长了也早已习惯了这种思考方式。很多重构的基础都建立于此,把重复代码拆分、重组,以达到耦合度更低的优化。

倒是另外一点让我觉得更受启发,那就是给现有代码做减法。无论是从需求上削减无用的功能,还是重用现成的轮子,尽量地保持代码库的精简,让维护工作变得简单。可能造轮子有时是必要的,可是如果对于语言和框架本身的标准 API 足够熟悉,再造工作也会轻松很多。

End

总而言之,十分推荐这本书,而且通篇读下来非常流畅,无论是语句还是排版,都可以算作可读性原则的实证。也许代码和诗文彼此相通,不管是程序员还是诗人作家,本质上都在追求用语言传播思想的艺术吧。