表面层次的改进
一、命名
1. 把信息装到名字里
选择更专业的词:就是要寻找更有表现力,更精准的词汇来进行命名,文章给出了一个可替换单词的表格:
单词 替换选择 send deliver, dispatch, announce, distribute, route find search, extract, locate, recover start launch, create, begin, open make create, set up, build, generate, compose, add, new 避免空泛的词汇:比如
tmp
,retval
这样的单词,除非有特殊的理由,比如:tmp
这个名字之应用于短期存在且临时性为其主要存在性素的变量。
循环迭代器中的i
,j
,k
也有更好的选择,比如user_i
能更好的表示这个循环索引是用来指示 user 的。使用具体的名字来替代抽象的名字:想要检测服务是否可以监听某个端口,就不要用
ServerCanStart()
这样的名词,最好用CanListenOnPort()
这样更加具体描述这件事情的名称。给变量名带上重要的细节:
- 对单位,编码方式等等进行一个解释,比如给带单位的变量,在后面带上单位,比如值为毫秒的变量后面加上
_ms
;还可以为未处理的数据前面加上一个raw_
- 对单位,编码方式等等进行一个解释,比如给带单位的变量,在后面带上单位,比如值为毫秒的变量后面加上
为作用域大的名字采用更长的名字:不应该把那些只有一两个字母的名字用在很大的作用域下;相对的,在小的作用域里面,就不要用太长的名字……
有目的地使用大小写、下划线等:比如 JavaScript 中,就建议,构造函数应该首字母大写,而普通的函数则是小写。献上:JavaScript 编码规范
2. 不会误解的名字
关键思想:多问自己几遍:“这个名字会被别人解读成其他的含义吗?”,要相信,一个好名字是不会被误解的
- 举例:用
filter()
时,阅读者并不知道,是要将特定目标从里面挑选出来还是过滤掉。
推荐策略
- 用 min 和 max 来表示(包含)极限:如果想要表示极限,而且这个极限是在取值范围内的,比如两位正整数,用
[10,99]
来表示,那么我们就可以用max_XXXX
表示最大的极限 99,用min_XXXX
表示最小的极限 10. 用 first 和 last 表示包含的范围:
[first, last]
用 begin 和 end 表示包含/排除范围:
[begin, end)
明确的布尔值命名:用 is, has, can, should 这样的词来使得布尔值更明确,避免使用反义名词
要和使用者的期望匹配:用户会期望
get()
或者size()
是轻量级的方法。可以用用computer*()
来代替复杂度很高的get*()
操作,用countSize()
或者countElements()
来替代复杂度很高的size()
等等- 例子:使用者很容易把
get*()
理解成一个很轻量的操作,他们可能认为get*()
的时间复杂度只有O(1)
?比如,getMean()
这个函数是用来遍历,计算出平均值,但是使用者可能就觉得这个计算复杂度会很低,调用它的代价会很小。最好用computerMean()
来代替它。
- 例子:使用者很容易把
二、审美
- 使用一致的布局,让读者很快就习惯这种风格
- 让相似的代码看上去相似
- 把相关的代码行分组,形成代码块
三、注释
注释的目的是让读者了解的和作者一样多
1. 写什么样的注释
1)不用写注释的地方
- 不要为那些从代码本身就能快速推断的事实写注释
- “好代码>好注释+坏代码”——不要用注释来粉饰那些烂代码和烂命名
2)需要写注释的地方
用注释记录思想:
- “导演评论”:可以加入一些注释,用来解释这段代码是如何运行的,或者评论这段代码
“记录瑕疵”:可以记录一些代码中的瑕疵,甚至可以利用某些标记,比如
标记 意义 TODO 我还有没处理的事情 FIXME 已知的无法运行的代码 HACK 对一个问题不得不采用比较粗糙的解决方案 XXX 危险!这里有重要问题 “常量注释”:利用注释来解释为什么这个常量是这个值
站在读者的角度
- 为意料之中的提问写上注释:比如为什么这里要这么实现?
- 为意料之外的行为写上注释:比如公布可能存在的陷阱:这个函数在某种情况下可能会存在问题
- 全局观注释:用来解释所有的部分是如何一起工作的,比如,类之间如何交互,数据如何在系统中流动,入口在哪里…比如:
1
2// 这个文件包含了一些辅助函数,为我们的文件系统提供了更便利的接口
// 它处理了文件权限及其他基本的细节 - 总结性注释:用来总结前面的代码块,使读者不至于迷失在细节中
2. 写言简意赅的注释
注释应当有很高的信息/空间率
让注释保持紧凑
避免使用不明确的代词(如,it,this 等等)
润色粗糙的句子
精确地描述函数的行为
- 比如文件中只包含
hello\n
这段文字,究竟认为是一行还是认为两行,所以利用“//计算文件包含多少行(\n)
”来代替“//返回文件的行数
”会更精准
- 比如文件中只包含
用输入输出举例来说明特别情况,举例:
1 | //Examle: Strip("abba/a/ba", "ab") returns "/a/" |
声明代码的意图:更高层次的意图,而不仅仅是这段代码干了什么。
- 比如注释:
//将价格从高到低排列
,而不仅仅注释说明:// 反向遍历队列
- 比如注释:
嵌入注释来帮助理解参数含义:
1 | void Conect(int timeout, bool use_encryption) { ... } |
- 采用信息含量高的词汇