编写可读代码的艺术

标签(空格分隔): 读书笔记


让代码更加易于理解

所有的事情都是为了让代码更加容易阅读, 衡量的标准为: 相比于代码行数, 更加倾向于其他人阅读这段代码所花费的时间

:

把信息塞进名字中

使用专业的单词

例如,不用Get, 而用Fetch或Download, 这要由上下文决定

避免空泛的名字

像tmp和retval, 除非使用它们有特殊的理由

使用具体的名字来更细致的描述事物

ServerCanStart()这个名字就比CanListenPort更不清楚

给变量名带上重要的细节

例如, 在值为毫秒的变量后面加上_ms, 或者在还需要转义的, 未处理的变量前面加上raw_

为作用域更大的变量采用更长的名字

出现的范围越大, 范围越广, 变量的名字含义应该越丰富

有目的地使用大小写, 下划线等

例如, 你可以在类成员和局部变量前面加上"_"来区分它们

不会误解的名字

阅读你代码的人应该理解你的本意

不要使用两义性的单词 定义一个值的下限和上限时, 使用maxmin, 对于包含的范围, firstlast是好的选择, 对于包含/排除范围, beginend是最好的选择

在为bool值命名时,

使用is和has这样的词来明确表示它是个boolean, 避免使用反义的词

小心用户对特定词的期望

例如: 用户会期望get()或者size()是轻量的方法

代码的审美

如果多个代码块做相似的事情, 尝试让它们有同样的剪影

在必要时, 可以用列对齐

如果在一段代码中提到A.B和C, 那么不要再另一段话里说B.C和A, 选定一个有意义的顺序, 不要改变它

用空行来把大块代码分成逻辑上的"段落"

该写什么样的注释

什么不需要注释

  • 能从代码本身中迅速推断的事实
  • 用来粉饰烂代码的"拐杖式注释"–应该把代码改好

你应该记录下来的想法包括

  • 对于代码写成这样而不是那样的内在理由
  • 代码中的缺陷, 使用像TODO:或者XXX:这样的标记
  • 常量背后的故事, 为什么是这个值

站在读者的立场上思考

  • 预料到代码中哪些部分会让读者说: “啊?” , 并且给它们加上注释
  • 为普通读者意料之外的行为加上注释
  • 在文件/类的级别上使用"全局观"注释来解释所有的部分是如何一起工作的
  • 用注释来总结代码块, 使读者不致迷失在细节中

写出言简意赅的注释

  • 当像it 和this 这样的代词可能指代多个事物时, 避免使用它们
  • 尽量精确地描述函数的行为
  • 在注释中用精心挑选的输入/输入例子进行说明(单元测试)
  • 声明代码的高层次意图, 而非明显的细节
  • 用嵌入的注释(如Function(/* arg = */...))来解释难以理解的函数参数, 在C#里, 可以使用命名实参
  • 用含义丰富的词来使注释简洁

简化循环和逻辑

把控制流变得易读

相对于追求最小化代码行数, 一个更好的度量方法是最小化人们理解它所需的时间

有几种方法可以让代码的控制流更易读

  • 在写一个比较时(while( bytes_expected > bytes_received)), 把改变的值写在左边, 把更稳定的值写在右边更好一些(while( bytes_received < bytes_expected ))
  • 重排if/else 语句中的代码块, 先处理正确的/简单的/有趣的情况
  • 尽量不要使用do/while循环, 仅在必要时使用三目运算符(:?)和goto
  • 把嵌套的代码块改写成线性的代码
  • 通常来讲可以使用提前返回来减少嵌套, 此种语句被称为"保护语句"

拆分超长的表达式

  • 引用"解释变量"来代表较长的子表达式
    • 他把巨大的表达式拆成小段
    • 它通过用简单的名字描述子表达式来使代码文档化
    • 帮助读者识别代码中的主要概念
  • 使用德摩根定理来操作逻辑表达式, 重写布尔表达式

变量与可读性

  • 减少变量
  • 减小每个变量的作用域
  • 只写一次的变量更好

重新组织代码

抽取不相关的子问题

把公共代码和项目专有的代码分开, 例如使用Common.dll

一次只做一件事

把想法变成代码

使用自然语言描述程序, 然后用这个描述来帮助你写出更自然的代码

少写代码

  • 从项目中消除不必要的功能, 不要过度设计
  • 重新考虑需求, 解决版本最简单的问题, 只要能完成工作就行
  • 经常性通读标准库的整个API, 保持对它们的熟悉程度

附加

测试与可读性

  • 每个测试的最高一层应该越简明越好. 最好每个测试的输入/输出都可以用一行代码来描述
  • 如果测试失败了, 它所发出的错误消息应该能让你容易跟踪并修正这个bug
  • 使用最简单的并且能够完整运用代码的测试输入
  • 给测试函数取一个有完整描述性的名字, 以使每个测试所测的东西都很明确.
  • 使测试易于改动和增加新的测试