重温《编写可读性代码的艺术》,记下的部分摘录和总结,以便日后回顾、反思
摘录&总结
宗旨
- 可读性基本定理总是优先于其他条例或原则
- 尽管减少代码行数是一个好目标,但把理解代码所需的时间最小化是一个更好的目标
- 写出新的团队成员能理解代码(命名同样适用)
命名
- 选择专业的词,避免空泛或意义模糊的名字
- 用具体的名字代替抽象的名字
- 给名字带上附加信息(如单位 MB、KB)
- 为作用域更大的命名取一个更长(更详细)的名字
- 采用一致的命名规范,有目的的使用大小写和下划线
- 对不同实体使用不同格式就像语法高亮一样,能帮你更容易的阅读代码
- google c++命名规范中,常量的格式是
而不是kConstantName
,目的是与宏区分开来,类成员变量使用下划线结尾,如CONSTANT_NAME
,与普通局部变量区分开来offset_
- 命名应该符合使用者的期望
-
、get
、length
等命名的方法,使用者期望调用它们是没有什么代价的(不会耗费性能)size
-
- 变量和方法定义选择一个有意义的顺序,始终一致的使用它
注释
- 好名字比好注释更加重要
- 帮助读者能够 更容易 理解代码的是好注释
- 不要为那些从代码本身就能 快速 推断的事实写注释
- 如果有注释能够比没有注释理解起来 快很多,那么注释是有可以的
-
name = '*'.join(line.split('*')[:2]) # 丢弃第二个'*'后面的所有东西
-
- 加入“导演评论”
-
# 出乎意料的是,对于这些数据用二叉树比用哈希表快40%
-
# 哈希运算得代价比左/右比较大得多
- 防止读者为了无谓的优化而浪费时间
-
# 作为整体可能丢掉几个词,这没有什么问题。要100%解决太难了
- 解释了自己的解决方法虽然有瑕疵,但并不影响正常使用,并表示自己未能找到完美的方案,不鼓励他人在此作无谓的优化
-
- 意料之中的提问,大部分人会产生疑惑的地方(为什么这么做,为什么直接用简单的方法)应该写上注释
- 公布可能的陷阱
- 连接失败一段时间后超时异常
- 性能问题,运行时间达到 O(num*depth), 嵌套很深的输入需要小心
- 全局观注释
- 总结性注释
- 这种注释也是对函数(或一段代码)所做的事情的总结,在读者深入了解细节之前就能得到该代码的主旨
控制流
- 把条件、循环以及其他对控制流的改变做得越自然越好(往往自然语言表述出来就是自然的,尝试先用自然语言描述逻辑)
- 逻辑处理顺序,有时这些倾向性会冲突,那么你就需要自己判断哪一种情况应该优先处理了,很多情况下这都会有很明确的选择
- 先处理掉简单的情况(例如先处理特殊情况,提前返回,减少分支数量)
- 先处理有趣的或者可疑的情况
- 先处理正逻辑
- 三目运算符应该不会对可读性造成负面影响的情况下使用
- 使用解释变量,用它来表示一个子表达式,提高可读性
- 使用德摩根定理
-
not (a or b or c) == (not a) and (not b) and (not c)
-
not (a and b and c) == (not a) or (not b) or (not c)
-
- 尝试从“反方向”解决问题
变量
- 消除中间变量(对可读性没有影响的变量)
- 缩小变量作用域
- 只写一次的变量更好
组织代码
- 创建大量通用代码,把一般代码和项目专有代码分开
- 积极地发现并抽取出不相关的子逻辑
- 看看某个代码块,问问自己:这段代码的高层次目标是什么?
- 对每一行代码,问一下:它是直接为目标工作的吗?这段代码的高层次目标是什么?
- 如果足够的行数在解决不相关的子问题,抽取代码到独立的函数中
- 简化已有接口
- 把一个方法中的所有操作保持在同一个抽象层次上
- 一次只做一件事
- 列出代码所做的所有“任务”
- 尽量把这件任务拆分到不同的函数中,或者至少是代码中不同段落中
- 最好读的代码就是没有代码
- 让你的代码库越小、越轻量级越好
- 创建越多越好的“工具”代码来减少重复代码
- 减少无用代码或没有用的功能
- 让你的项目保持分开的子项目状态
测试
- 使测试易于阅读和维护
- 让错误信息具有可读性
- python中的unittest模块的assertEqual方法比assert的错误信息更具体
总结
- 写代码时,应该时常问下自己:新的团队成员能否理解自己的代码
- 所谓的工程学就是关于把大问题拆分成小问题,再把这些问题的解决方案放回一起
- 为代码增加一个函数存在一个小的(却有形的)可读性代价(你需要暂时跳到另一个函数中去,你回来之后可能会忘了些什么)
- 一段代码抽出成一个函数的准则是:这样做是否提高了可读性,如果当前并不关注于这段代码的细节,那么是应该抽成一个函数的
- 一次只做一件事,先列出方法要做的任务,尽量保持一个方法中的操作在同一个抽象层次上
- 先用自然语言描述逻辑