clean code 读书笔记

/ 技术文章 / 0 条评论 / 2080浏览

clean code 读书笔记

clean_code_mind_map

前提

  1. 破窗理论:设计良好的架构,如果维护不当,也会随着时间腐化
  2. 重构要一直进行,而不是到不得不做才开始
  3. 好的系统是演进出来的。所有事物都是如此。软件也不例外,不要尝试一开始就构建一个可以抽象非常好的系统,没有人可以做到这样。
  4. 一般软件的生命周期只有3-5年,所以,一定要考虑收益比
  5. 好的代码是锦上添花,不要动不动上升到代码写得烂,公司就倒闭这种夸张程度
  6. LeBlanc:稍后等于永远不
  7. 代码质量与思考时间成正比,也就与成本成正比。好的代码也必须用更长的时间来思考。成本思维一定要有
  8. 代码从上到下,越到下面,个人风格越强烈,可读性的好与不好越难评判孰优孰劣,因此,完全依赖个人。一段代码的好与坏并不是二元论,不同人有不同的看法,这也是编码最接近写作的地方。所以,没有充足的理由不要妄下断论。

什么是Clean Code

开始评判什么是好代码的时候,一定先要对什么是好代码,什么是糟糕的代码有一个明确的定义,否则,谈论代码好与糟糕毫无意义?

原则:

当明确了什么是 Clean Code,那么也就明确了什么是糟糕的代码,如何将糟糕的代码修改为好代码?

数据支撑

仅仅是前后一致的缩进就减少了代码的缺陷 软件生命周期的80%时间在维护

实践建议

整洁代码的意义

项目易维护,产出比高。

Clean Code 的建议(注意是建议)

Clean Code 的建议可以从多个维度来描述,比如从原则方面,可以从抽象层次来描述。

软件的抽象

对象和数据结构

  1. 过程式代码便于在不该动既有数据结构的情况下,添加新函数,但是新的数据结构很难。
  2. 面向对象便于不改动既有函数的前提下,添加新类,但添加函数非常困难。
  3. 根据情况决定使用1还是2

下面只从可读性和抽象层次来说明,要真正的 Clean Code 不是简单的看两本书就行,需要阅读大量的书籍,多年的实战,十年编程,毫不夸张,所以,程序员要保持一颗谦卑之心。

变量

  1. 用命名常量替代魔数:这条放在第一条,一个原因是这是变量命名最基本的要求,另外一个原因是,很多人连这个基本的要求都没达到。
  2. 像给自己的孩子命名般谨慎地给变量命名:意在说明变量命名要谨慎,而且变量命名很难。
  3. 用具体的而不是抽象的单词命名
  4. 不要因为害怕遍历长而自定义缩写。比如 srv 表示server。
  5. 如果非要用缩写,一定要用专业缩写,对于领域特定的缩写,应该注明全名。
  6. 变量要考虑语境,port.getNo() 已经很明确。port.getPortNo()反而有点多余
  7. 如果有单位,把单位加上。比如 expiredMs,distanceMiles。
  8. 通常来讲,加上像is、has、can或should这样的词,可以把布尔值变得更明确。
  9. 推荐用begin和end来表示包含/排除范围,一般为左闭右开。涉及到区间,最好写明注释。
  10. 推荐用first和last来表示包含的范围
  11. 命名避免多义性:不会误解的名字是最好的名字——阅读你代码的人应该理解你的本意,并且不会有其他的理解。
  12. 避免违背惯例:很多程序员都习惯了把以get开始的方法当做“轻量级访问器”,所以不要在getXX方法中继续复杂处理。size方法应该是O(1) 是否需要定义变量的标准:1. 澄清某个概念;2. 拆分复杂表达式;3. 压缩容易代码

函数

  1. 只做一件事:这个是非常难准确定义的,也是最具争议的地方。
  2. 一个函数的长度最好不要超过整个屏幕。这仅仅是建议,绝大多数也是可以做到的。
  3. 一般代码和项目专有的代码分开。
  4. 函数参数多可以考虑将多个参数构建对象来承载,但是构成对象的参数必须是应该用对象(各个参数为抽象概念的一部分),而不能只是为了减少参数而构建为对象。
  5. 真实情况往往非常复杂,所以返回值不是必须要再返回值中承载(有些编程语言支持多个参数返回),参数作为在某些场景下也是可以的。函数的参数不必必须限定在 3 个。很多时候要看具体场景。千万不能教条化,好代码的难度在于这些特殊处理之处见真功夫,而不是在确定的地方
  6. 一个函数到标准库级别,如果超过5层嵌套,基本上可读性会立马下降非常多,过度的包装是易读的杀手。所以,不要动不动就封装函数,具体要看场景。
  7. 有些程序员认为函数中永远不应该出现多条return语句。这是胡说八道。从函数中提前返回没有问题,而且常常很受欢迎。
  8. 判断条件左侧是变化的值,右侧是相对固定的值。这样更符合人类阅读习惯。
  9. 循环中有 break 和 continue 的代码 99% 可以被优化,优化方法包括抽取子方法和调整 if 语句顺序
  10. 负逻辑更简单并且更有趣或更危险的一种情况,那么会先处理它
  11. 首先处理正逻辑而不是负逻辑的情况。例如,用if(debug)而不是if(!debug)。
  12. 先处理掉简单的情况。这种方式可能还会使得if和else在屏幕之内都可见,这很好。
  13. 较长的表达式引入解释变量,总结变量
  14. 对于增加可读性的变量,要加,对于可读性作用不大的变量要减少。判断依据是可读性,大多数依赖个人风格
  15. 过多小函数实际上对可读性是不利的,因为读者要关注更多东西,并且按照执行的路径需要跳来跳去。
  16. 一个大函数拆分成多个小一些的函数是好的。一开始应该在函数内部组织代码,使得它感觉像是有分开的逻辑段。然后随着代码的演进,根据单一功能的代码量和可1. 复用性决定是否抽取为函数。如果某个功能的代码量很大已经影响可读性了,抽取出独立的函数。某个功能的代码在其他地方也用到了,抽取为独立的函数。
  17. 个人觉得将一个函数内的所有操作都作为同一抽象层次,过于理想化,尽量这样做,但不可过于教条地遵守。
  18. 封装条件:将表达意图的判断条件封装为函数提高可读性
  19. 避免否定性条件:if(buffer.isEmpty())比if(!buffer.isEmpty())要好理解的多

  1. 单一职责原则:类有且只有一个加以修改的理由。理想很丰满,现实很骨感,切记生搬硬套。
  2. 类名要具体,根据单一职责,类就不会太大
  3. 控制反转,依赖注入,面向切面是设计思想,与语言无关
  4. 必须为每个类创建接口,字段和行为必须分开到数据类和行为类中,属于典型的教条主义,这都是一些初学者易犯的错误,当然初学者教条主义一些也没有什么坏处,但必须认识到软件的的执行是精确的,但软件的编码方式是一门艺术,运用之妙,存乎一心。
  5. kent beck简单设计的原则:运行所有测试,不可重复,表达力程序员的意图,尽可能减少类和方法的数量
  6. 用多态替代switch和if/else
  7. 避免传递依赖:A依赖B,B依赖C,避免 A直接依赖C

注释

  1. 注释是最核心的目的是将代码之外的信息传递给读者,尽量帮助读者了解得和作者一样多。
  2. 当你写代码时,你的脑海里会有很多有价值的信息。当其他人读你的代码时,这些信息已经丢失了——他们所见到的只是眼前的代码。注释就是把代码中无法体现的关键信息记录下来
  3. 无用的注释会占用阅读真实代码的时间,并且每条注释都会占用屏幕上的空间。
  4. 注释是不可少的
  5. 如果代码来描述得很清楚,注释是不必要的
  6. 绝大多数注释应该阐明为什么这么做,而不是做了什么。比如不这样做会存在什么bug。在该处理异常的地方,不处理,是一个算法的描述等等
  7. 注释还有一个作用是警示,一般用于提醒反直觉的做法,修改了某些潜在的bug
  8. 为普通读者意料之外的行为加上注释。
  9. TODO,不要尝试消除全部TODO,而应该关注什么时候完成它。
  10. 添加注释的时机是你过了一段时间再读代码或者其他人review代码,发现代码已经无法修改得更好,而需要注释来更快速地理解代码,这个时候注释就是必须的。
  11. 在文件/类的级别上使用“全局观”注释来解释所有的部分是如何一起工作的。
  12. 注释代码块,使读者不致迷失在细节中。
  13. 在 JDK 的源码中,方法上的注释非常详细,甚至会有示例,如果仔细观察,会发现这些详尽的带有示例的程序,通常是那些靠第一印象确定不了的。

代码格式

参考

  1. https://blog.csdn.net/wenxueliu/article/details/94914822
  2. https://www.cnblogs.com/edisonchou/p/edc_clean_code_notes.html