Clean Code 读书总结

Clean Code 读书总结

整洁代码

  • 稍后等于永不
  • 始终保持代码的整洁
  • 整洁的代码只做好一件事
  • 果断决绝,就事论事,没有犹豫或不必要的细节

有意义的命名

  • 避免误导
    • 小写的l和1
  • 做有意义的区分
    • 废话都是冗余,Variable(变量)一词永远不应当出现在变量名中。
    • 变量moneyAmount和amount没有任何区别,theMessage和message没有任何区别
  • 使用读的出来的名称
  • 使用可搜索的名称
    • 名称的长短应与其作用域的大小相对应
    • 若变量和常量可能在代码中多处使用,应赋予其以便于搜索的名称
  • 避免使用编码
    • 随着时代的进步,变量类型已经具体化,现阶段减少变量的前缀和后缀的使用
    • 接口命名的编码尽量废弃,例如进入的时候的加I
  • 避免思维映射
    • 避免单字母命名
    • 聪明程序员和专业程序员之间的区别在于,专业程序员了解,明确才是王道
  • 类名
    • 类名和对象名应该是名词和名词短语
  • 方法名
    • 方法名应当是动词或动词短语,属性访问器,修改器和断言应该根据其值命名,具体参考javaBean
    • 可以考虑将相应的构造器设置为Private,强制使用这种命名
  • 别扮可爱
    • 言到意到,意到言到
  • 每个概念对应一个词
    • 给每个抽象概念选一个词,并且从一而终,fetch(拿来)、retrieve(收回),get 命名
  • 别用双关语
    • 避免一词多义,一个词汇表达一个意思,append,add,insert
  • 使用解决方案领域名称
    • 只有程序员才会读你的代码,尽量使用自己的专业术语
  • 使用源自所涉领域的名称
  • 添加有意义的语境,让别人知道这个是什么作用
  • 不要添加没用的语境,精确
  • 使用之前说的,提高代码可读性,重构的时候也是立竿见影

函数

  • 短小,细粒度尽量细,不超过20行,函数缩进层级不该多一层或两层
  • 函数应该只做一件事,做好这件事,只做这件事
  • 每一个函数一个抽象层级
    • 要确保函数只做一件事,函数的语句都要在同一抽象层级上。细节分放置后面
    • 自顶向上读代码:向下规则
  • 对于switch语句,我们的规矩是指出现一次,用于创建多态对象,而且隐藏在某个继承关系中。就是工厂模式,根据传入的值,返回不同new 的对象。但就事论事,可能会部分违反或者全部违反。
  • 使用描述性的名称
    • 函数行数越小,功能越集中,越便于容易取个好名字,
    • 长而具有描述性的名称
  • 函数参数
    • 最理想的没有参数,慢慢累加,应尽量避免三个参数函数,除非有足够的理由
    • 一元函数形式,对于事件和转换,命名要体现出来,转换尤其体现在返回值上面
    • 不要传入标识参数,例如布尔值
    • 二元函数适用单个值的有序组成部分,例如坐标
    • 三个参数以上应该封装成对象
    • 函数名取个好名字,见名知意
    • 普遍而言,应尽量避免使用输出函数,如果必须要修改某种状态,就修改所属对象的状态吧。
  • 分隔指令与询问
    • 函数要么做什么事,要么回答什么事,但二者不可兼得,函数应该修改某对象的状态,或者返回该对象的有关信息。
    • 将指令和询问分开
  • 使用异常替代返回错误码
    • 简化代码流程,知道一个错误直接的得到错误信息
  • 抽离try/catch代码,里面只放一个函数
  • 消除重复代码
  • 结构化编程,保持单入单出,goto只在大函数有用避免使用
  • 一开始不按照规则打代码,先完成功能,然后遵循规则,分解函数,修改名称,消除重复,缩短和重新安置方法,

注释

  • 注释存在的时间越久远,就离其描述代码越远,越变得全然错误,因为程序员不能坚持注释。
  • 代码在变动,注释不总是随着变化,尽量用代码表示意义
  • 只有代码能忠实告诉你它做的事,那是唯一真正准确的信息来源。
  • 注释不能美化的糟糕代码
    • 带有少量注释的整洁而又表达力的代码要比带有大量注释零碎而复杂的代码像样的多
  • 用代码阐述
  • 唯一的好注释就是不写注释
  • 提供信息的注释
  • 对意图信息的解释
    • 注释不仅提供了有关实现有用信息,而且还提供了某个决定后面的意图。
  • 记得处理TODO代码

格式

  • 从上往下读,从左往右,空白行增加可读性
  • 紧密相关的代码应该相互靠近
  • 相关函数应放在一起
  • 代码尽量短小,死守80个字符上限有点僵化,而且不反对代码长度达到100个字符或120个字符,
  • 用空格区分运算符的优先级

对象和数据结构

  • 方法不应调用有

错误的处理

  • 特例模式,创建一个类或者配置一个对象,用来处理特例
  • 别返回null,避免空指针异常,可以返回Collects.emptyList,代码会更加简洁
  • 别传递null,给自己和别人造成困扰
  • 整洁的代码是可读的,如果将错误处理隔离看待,独立于主要逻辑之外,就能写出强固而整洁的代码。

边界

  • 一些情况下,我们使用别人的接口,需要用别人的代码
  • 我们不建议总是以这种方式封装Map的使用,我们建议不要将Map(或是在边界上的其他接口)在系统中传递,如果类似Map这样的接口,就把它保留在类或近亲类中。避免从公共api中返回边界接口,或将边界接口作为参数传递给公共API
  • 制作学习性测试,保证接口的稳定
  • 编写想要的接口,好处在于可控
  • 一个良好的软件设计,无需巨大的投入和重写即可进行修改,边界代码需要清晰的分割和定义了期望的测试,尽量对代码做上层封装,这样对代码的修改减少

单元测试

  • TDD三条定律
    • 1、在编写不能通过的单元测试前,不可编写生产代码
    • 2、只可编写刚好无法通过的单元测试,不能编译也算不同过
    • 3、只可编写刚好足以通过当前失败测试的生产代码
  • 保持测试代码整洁
  • 整洁的测试代码重要的在于可读性,明确,简洁,还有足够的表达力。
  • 整洁的测试还要遵循5条规则
    • 快速,测试要快
    • 独立,测试应该相互独立
    • 可重复,应该可在任何环境中重复通过
    • 自足验证,测试应该有布尔值输出,不应该查看日志文件来确认测试是否通过
    • 及时,测试应及时编写

  • 系统应该由许多短小的类而不是少量巨大的类组成。每个类封装一个权责,只有一个修改的原因,并与少数其他类一起协同达成期望的系统行为。
  • 一开始就做对系统纯属神话,反之,我们应该只去实现今天的用户故事,然后重构,明天再拓展系统、实现新的用户故事。这就是迭代和增量敏捷的精髓所在。
  • 代码层面和架构层面分离开,用测试来驱动架构,从简单到演化精致,没必要先做大的设计
  • 最佳的系统架构由模块化的关注面领域组成,每个关注面均用纯java(或其他语言)对象实现。不同领域之间用最不具有侵害性的方面或类方面工具整合起来。这种架构能测试驱动,就像代码一样。
  • 拥有模块化关注面的POJO系统提供的敏捷能力,允许我们基于最新的知识做出优化、时机刚好的决策。决策的复杂性也降低了
  • 有了标准,就更易复用想法和组件、雇佣和拥有相关经验的人才,封装好点子,以及将组件连接起来。不过,创立标准的过程有时却漫长到行业等不及的时候,有些标准没能与它要服务的采用者的真实需求相结合。
  • 无论是设计系统或单独的模块,别忘了使用大概可以可工作的最简单方案。

迭进

  • 简单设计规则1:运行所有测试
    • 设计必须制造出如预期一般工作的系统
  • 简单设计规则2-4:重构
    • 测试消除了对清理代码就会破坏代码的恐惧
    • 提高内聚性,降低耦合度,切分关注面,模块化系统性关注面,缩小函数和类的尺寸,选用更好的名称
  • 不可重复

并发编程

  • 对象是过程的抽象,线程是调度的抽象
  • 并发是一种解耦的策略,什么(目地)和何时(时机)分解开。在单线程,目的和实际紧密耦合
  • 并发会在性能和编写额外代码上增加一些开销
  • 正确的并发是复杂的,即便对于简单的问题也是如此
  • 并发的缺陷并非总能重现,所以常被看作偶发事件而忽略,并未当作真的缺陷看待
  • 并发常常需要对设计策略的根本性修改
  • 并发的防御原则
    • 单一权责原则:并发相关代码有自己的开发、修改和调优生命周期,开发相关代码有自己要对付的挑战,和非并发相关代码不同,分离并发相关代码与其他代码
    • 限制数据作用域:谨记数据封装,严格限制对可能被共享的数据的访问
  • 使用对象副本,避免共享数据
  • 生产者-消费者模型
    • 一个或多个生产者线程创建某些工作,并置于缓存或队列之中,一个或多个消费者线程冲队列中获取并完成这些工作。生产者和消费者之间的队列是一种限定资源。
  • 读者-作者模型
    • 当存在一个主要为读者线程提供信息源,但只偶尔被作者线程更新的共享资源,吞吐量就会是个问题,增加吞吐量,会导致线程饥饿和过时信息积累。更新吞吐量。协调读者线程,不去读作者线程正在更新的信息,这是辛苦的平衡工作。作者线程倾向于长期锁定许多读者线程,从而导致吞吐量的问题。
    • 挑战之处在于平衡读者线程和作者线程的需求,实现正确的操作,提供合理的吞吐量,避免线程饥饿
  • 宴席哲学家
    • 线程相互竞争资源,学习基础算法,理解其解决方案
  • 警惕同步方法的依赖
    • 避免使用一个共享对象的多个方法
  • 保持同步区域的微小
    • 锁是昂贵的,带来了延迟和额外的开销,尽可能少的设计临界区
  • 很难编写正确的关闭代码
    • 尽早考虑关闭问题,尽早令其工作正常。这会花费比你预期更多的时间。检视既有算法,因为这可能会比想象中难的多。
  • 测试线程代码
    • 编写有潜力暴露问题的测试代码
    • 将伪代码看作可能失败的线程问题:不要将系统错误归咎于偶发事件
    • 先使非线程代码可工作:不要同时追踪非线程缺陷和线程缺陷。确保代码在线程之外可工作
    • 编写可拔插的线程代码
    • 编写可调整的线程代码
    • 运行多于处理器数量的线程:切换任务时会发生一些事
    • 在不同平台上运行:尽早并经常在所有目标上运行线程代码
    • 调整代码并强迫错误发生
  • 不要锁定不必要的代码

逐步改进

  • 编程是一种技艺甚是科学的东西.要编写整洁代码,必须先写肮脏代码,再清理它。

JUnit内幕

  • 所有的if和for都要覆盖
  • 重构是一种不停试错的迭代过程

重构

味道与启发

别人的总结

  • http://blog.csdn.net/deng0zhaotai/article/details/44418497

你可能感兴趣的:(java,读书笔记)