最近读了《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哲学中,一个函数只做一件事。
- 对于用到的语言,第三方库要尽量掌握,并熟悉常用的函数。
单元测试可读性
- 测试代码提高可读性要遵循一个原则是:对用户隐藏不重要的细节,将重要的细节进行展示。
- 测试的输入内容应该是完全覆盖被测代码,并且在满足这一前提下是最简单的
- 好的代码是更加容易测试的
- 在测试代码中,可以使用帮助函数来简化测试代码。