编写可读代码的艺术

#前言 本书旨在帮助你把代码写的更好 [查看原书请点我 O(∩_∩)O](http://pan.baidu.com/s/1o6nZqHG) ##第1章 代码应当易于理解 ###是什么让代码变得“更好” ###可读性基本定理 代码的写法应当使别人理解它所需要的时间最小化 ###总是越小越好吗 把理解代码所需的时间最小化是一个更好的目标 ###理解代码所需的时间是否与其他目标有冲突 根本不会相互影响 ###最难的部分 经常想其他人是否会觉得你的代码容易理解,需要额外的时间 #第一部分 表面层次的改进 选择好的名字、写好的注释以及把代码整洁地写成更好的格式 ##第2章 把信息装到名字里 ###选择专业的词 术语上区分它的职能、找到更有表现力的词 ###避免像tmp和reveal这样泛泛的名字 好的名字应当描述变量的目的或者它所承载的值 如果你需要使用像tmp、lt或者retval这样空泛的名字,那么你要有个好的理由 ###把具体的名字带替抽象的名字 在给变量、函数或者其他元素命名时,要把它描述的更具体而不是更抽象 ###为名字附带更多信息 如果关于一个变量有什么重要事情要读者必学知道,那么是值得把额外的“词”添加到名字中的。 带单位的值、附加其他重要属性 ###名字应该有多长 名字不能太长 在小的作用域里可以使用短的名字 输入长名字————不再是个问题(编辑器的“单词补全”功能) 首字母缩略词和缩写 丢掉没用的词 ###利用名字的格式来传递含义 驼峰类名、下划线方法名、常量驼峰加kConstant前缀、宏是全大写下划线分词、构造函数首字母大写、jQuery对象前加$ 有目的地使用大小写、下划线等 ##第3章 不会误解的名字 要多问自己几遍:“这个名字会被别人解读成其他的含义吗?” ###例子:Filter() 二义性词,不知道其含义是“挑出”还是“减掉” ###例子:Clip(text,length) 二义性词,可能是从尾部删除,也可能时裁掉最大长度为length的一段 ###推荐用first和last来表示包含的范围 命名极限最清楚的方式是在要限制的东西前加上max_或者min_。 ###推荐用begin和end来表示包含/排除范围 ###给布尔值命名 当为布尔变量或者返回布尔值的函数选择名字时,要确保返回true和false的意义很明确。 最好避免使用反义名字。如'disable_ssl'。 ###与使用者的期望匹配 有些名字之所以会让人误解是因为用户对它们的含义有先入为主的印象,就算你的本意并非如此。在这种情况下,最好放弃这个名字而改用一个不会让人误解的名字。 ###例子:如何权衡多个备选名字 分析每个备选名字,考虑各种让人误解的可能性。 ##第4章 审美 让代码变得更易读有三条原则: . 使用一致的布局,让读者很快就习惯这种风格 . 让相似的代码看上去相似 . 把相关的代码行分组,形成代码块 ###为什么审美这么重要 让人愉悦的代码更容易阅读 ###重新安排换行带来保持一致和紧凑 ###用方法来整理不规则的东西 使代码“看上去漂亮”通常会带来不限于表面层次的改进,它可能会帮你把代码的结构做的更好。 ###在需要时使用列对齐 ###选一个有意义的顺序,始终一致地使用它 有一大堆get参数要获取,我们对代码中每个获取的顺序有一些想法: . 让变量的顺序与对应的HTML表单中字段的顺序相匹配 . 从“最重要”到“最不重要” . 按字母顺序排序 ##第5章 改写什么样的注释 注释的目的是尽量帮助读者了解得和作者一样多 ###什么不需要注释 不要为那些从代码本身就能快速推断的事实写注释 不要为了注释而注释 不要给不好的名字加注释————应该把名字改好 ###记录你的思想 写代码时有过重要想法 ###站在读者的角度 想象你的代码对于外人来讲看起来是什么样子的 公布可能的陷阱 全局观注释,考虑到新人加入,让她熟悉代码库 ###最后的思考————克服“作者心理阻滞” ##第6章 写出言简意赅的注释 注释应当有很高的信息/空间率 ###让注释保持紧凑 ###避免使用不明确的代词 如it、this ###润色粗糙的句子 ###精确的描述函数的行为 `Return the number of lines in this file` 和 `Count how many newline bytes('\n') are in the file` ###用输入/输出例子来说明特别的情况 Example ###声明代码的意图 What you want do ###“具名函数参数”的注释 默认参数 `Connetc(timeout = 10, user_encryption = false)` 做不到,用`Connet(/* timeout_ms= */ 10, /* use_encryption = */ false)` ###采用信息含量高的词 如果你感觉到一段注释太长了,那么可以看看是不是可以用一个典型的编程场景来描述它 #第二部分 简化循环和逻辑 试着最小化代码中的“思维包袱” ##第7章 把控制流变的易读 把条件、循环以及其他对控制流的改变做得越“自然”越好。运用一种方式使读者不用停下来重读你的代码 ###条件语句中参考的顺序
比较的左侧 比较的右侧
“被问询的”表达式,它更倾向于不断变化的 用来做比较的的表达式,它的值更倾向于常量
###if/else语句块的顺序 . 首先处理正逻辑而不是负逻辑的情况。例如,用if(debug)而不是if(!debug)。 . 先处理掉简单的情况。这种方式可能还会使if和else在屏幕之内都可见 . 先处理有趣的或者是可疑的情况 ###?:条件表达式(又名“三目表达式”) 相对于追求最小化代码行数,一个更好的度量方法是最小化人们理解它所需的时间。 默认情况下使用if/else。三目运算符?:只有在最简单的情况下使用 ###避免do/while循环 > 我的经验是,do语句是错误和困惑的来源……我倾向于把条件放在“前面我能看到的地方”。其结果是,我倾向避免使用do语句。 ###从函数中提前返回 ###臭名昭著的goto 应该避免使用goto ###最小化嵌套 嵌套很深的代码很难以理解 当你对代码做改动时,从全新的角度审视它,把它作为一个整体来看待 通过提早返回来减少嵌套 ###你能理解执行的流程吗? 不要让代码中使用“线程”、“信号量”、“异常”、“函数指针和匿名函数”、“虚方法”过多让实现流程变的高级难懂。 ##第8章 拆分超长的表达式 把你的超长表达式拆分成更容易理解的小块 ###用做解释的变量 临时中间变量 ###总结变量 ###使用德摩根定理 分别取反,转换与/或 ###滥用短路逻辑 要小心“智能”的小代码————它们往往以后会让别人读起来感到困惑。 ###例子:与复杂的逻辑战斗 struct Range{ int begin; int end; //For example,[0,5) overlaps with [3,8) bool OverlapsWith(Range other); } 相反比较 bool Range::OverlapsWith(Range other){ if(other.end <= begin) return false; if(other.begin >= end) return false; return true; } ###拆分巨大的语句 提取公用部分放入函数作为总结变量 ###另一个简化表达式的创意方法 定义宏 ##第9章 变量与可读性 1. 变量越多,就越难全部跟踪它们的动向 2. 变量的作用域越大,就更需要 跟踪它的动向越久 3. 变量改变得越频繁,就越难以跟踪它的当前值 ###减少变量 没有价值的临时变量 减少中间结果 减少控制流变量 ###缩小变量的作用域 让你的变量对尽量少的代码行可见。 ###只写一次的变量更好 操作一个变量的地方越多,越难确定它的当前值。 ###最后的例子 #第三部分 重新组织代码 函数级别对代码做的更大的改动 ##第10章 抽取不相关的子问题 1. 看看某个函数或者代码块,问问自己:这段代码高层次的目标是什么? 2. 对于每一行代码,问一下:它是直接为了目标而工作吗?这段代码高层次的目标是什么呢? 3. 如果足够的函数在解决不相关的子问题,抽取代码到独立的函数中。 把一般代码和项目专有的代码分开 ###介绍性的例子:findClosestLocation() ###纯工具代码 ###其他多用途代码 子代码自称一体后改进它变得更容易 ###创建大量通用代码 通用代码很好,因为“它完全地从项目的其他部分中解耦出来” ###项目专有的功能 ###简化已有接口 你永远都不要安于使用不理想的接口 ###按需重塑接口 ###过犹不及 别分的太细,多个小函数对可读性不利 ##第11章 一次只做一件事 应把代码组织得一次制作一件事情。 ###任务可以很小 投票的例子 ###从对象中抽取值 ###更大型的例子 ##第12章 把想法变成代码 > 如果你不能把一件事情解释给你祖母听的话说明你还没有真正理解它。 ###清楚地描述逻辑 用自然语言描述逻辑 ###了解函数库是有帮助的 编写精炼代码的一部分工作是了解你的库提供了什么。 ###把这个方法应用于更大的问题 自然语言描述逻辑、适当递归调用自身 ##第13章 少些代码 最好读的代码就是没有代码 ###别费神实现那个功能————你不会需要它 ###质疑和拆分你的需求 ###保持小代码库 让你的代码库越小,越轻量级越好 删除没用的代码 ###熟悉你周边的库 每隔一段时间,花15分钟阅读标准库中的所有函数/模块/类型的名字 成熟的库中,每行代码都代表大量的设计、调试、重写、文档、优化和测试。 ###例子:使用Unix工具而非编写代码 通过以下方法避免编写新代码: . 从项目中消除不必要的功能,不要过度设计。 . 重新考虑需求,解决版本最简单的问题,只要能完成工作就行。 . 经常性地通读标准库的整个API,保持对它们的熟悉程度。 #第四部分 精选话题 ##第14章 测试与可读性 ###使测试易于阅读和维护 测试应当具有可读性,以便其他程序员可以舒服地改变或者增加测试 ###这段测试什么地方不对 ####使这个测试更可读 对使用者隐去不重要的细节,以便更重要的细节会更突出 ####创建最小的测试声明 大多数测试的基本内容都能精炼成“对于这样的输入/输出情形,期望有这样的行为/输出” ####实现定制的“微语言” ###让错误消息具有可读性 了解显示错误的库 #####手工打造错误消息 错误消息应当越有帮助越好 ###选择好的测试输入 基本原则是,你应当选择一组最简单的输入,它能完整地使用被测代码 又简单又能完成工作的测试值更好 #####一个功能的多个测试 ###为测试函数命名 `Test__()` ###那个测试有什么地方不对 ###对测试较好地开发方式 你会开始把代码写得容易测试! ###走得太远 . 牺牲真实代码的可读性,只是为了使能测试 . 着迷于100%的测试覆盖率 . 让测试成为产品开发的阻碍 ##第15章 设计并改进“分钟/小时计数器” ###问题 跟踪过去一分钟和一个小时里Web服务器传输了多少字节。 ###定义类接口 ###尝试1:一个幼稚的方案 ###尝试2:传送带设计方案 ###尝试3:时间桶设计方案 ###比较三种方案 #附录 ##深入阅读 ###关于写高质量代码的书 ###关于各种编程话题的书 ###历史上重要的书目

标签:<a href="/?tag=编程">编程</a>,<a href="/?tag=代码">代码</a>