'编写可读代码的艺术'读书笔记

最近读了《the art of readable code》这本书,书的内容是叫你如何写出可读性高的代码。觉得里面的很多例子和观点有很大的参考价值,所以在这篇博客中记录下来。

书中有个很强的观点,代码是给人看的,不是给机器看的。所以写代码要将可读性放到第一位。写代码时要时刻考虑这段代码别人是不是容易阅读。
全书分为四部分,分别为:

  • 代码外观上的改进
  • 简化循环和代码逻辑
  • 重新组织代码
  • 单元测试可读性

代码外观上的改进

这一部分主要是从变量命名、函数命名、注释等方面介绍如何提升代码可读性。

命名和注释

“代码中最困难的两件事情,是命名和缓存失效”。可见命名的困难性。在选择名称时,我们遵循如下原则:

  • 选择能够准确表达代码意图的名称
    1
    2
    3
    // GetPage函数不能表示page从哪里获取。推荐使用FetchPage和DownloadPage进行替换。
    def GetPage(url):
    ...
    下面展示了英文中单词对应的同义词
单词 同义词
send deliver,dispatch,announce,distribute,route
find search,extract,locate,recover
start launch,create,begin,open
make add, push, enqueue
  • 避免使用泛化的名称,比如tmp、retval之类的东西。
    但在一些特殊情况下可以使用,比如循环、交换两个数时的临时变量中
  • 名称中附带额外信息
    下面展示了一些具体的例子
函数参数 推荐重构后的内容
Start(int delay) delay -> delay_secs
CreateCache(int size) size -> size_mb
ThrottleDownload(float limit) limit -M max_kbps
  • 根据变量的作用域选择合适的名称
    变量的作用域如果比较长,则变量名称尽量多携带信息;变量作用域如果比较短,则变量名称推荐用简单的、简短的。

  • 英文中一些推荐变量命名做法

    • 使用min和max表示下限和上限(包含)
    • 使用first和last表示范围,其中last包含最后一个数
    • 使用begin和end表示范围,其中end是最后一个数的下一个数
  • 布尔命名中避免携带否定词
    disable_ssl就没有use_ssl 好
  • 代码需要有段落
  • 如果代码表达的意思已经很明确了,那么没有必要添加注释

简化循环和代码逻辑

  • 尽早从函数返回(卫语句使用)
  • 避免使用do-while循环语句
  • 减少代码中的嵌套(比如可以使用提前返回)
  • 代码中的巨大表达式要进行简化
  • 代码中使用的变量越多,程序阅读起来就越困难
    1
    2
    3
    下面的now完全没有必要,直接用后面的内容替换now就行
    now = datetime.datetime.now()
    root_message.last_view_time = now
  • 尽量降低变量的作用域。(全局变量越少越好,其实就是降低耦合度)
  • 变量应该在需要的时候进行定义,而不是在函数的开头就定义当前函数中需要的所有变量
  • 变量改变的越多,追踪变量的当前值就越困难(尽量使用只写一次的变量,比如java中的final,go中的const等)

重新组织代码

  • 首先用自然语言描述代码需要完成的功能,然后在进行实现;这个方法在重构代码时也非常有用。
  • 尽量创建通用的代码,与项目无关的代码尽量放到独立的模块中,比如util模块中。
  • 代码应该只做一件事情(do only one task at a time);借鉴:unix哲学中,一个函数只做一件事。
  • 对于用到的语言,第三方库要尽量掌握,并熟悉常用的函数。

单元测试可读性

  • 测试代码提高可读性要遵循一个原则是:对用户隐藏不重要的细节,将重要的细节进行展示。
  • 测试的输入内容应该是完全覆盖被测代码,并且在满足这一前提下是最简单的
  • 好的代码是更加容易测试的
  • 在测试代码中,可以使用帮助函数来简化测试代码。