《Clean Code》阅读笔记

时间:2023-12-24 21:28:07
  • Chapter 2  命名

    • 命名要表现意图
    • 避免歧义和误导,增强区分
    • 命名可读性:便于发音,增强印象,便于交流
    • 命名可查性:增强区分,便于搜索
    • 类和对象的命名:名词或名词短语
    • 方法的命名:动词或动词短语
    • 使用仅表述单一概念的词,如 get,避免多概念的词,如 fetch
    • 使用行业术语及业务术语
  • Chapter 3  方法

    • 尺寸:越小越好,不应超过20行
    • if、else、while 等 statement 不应超过一行
    • 单一责任
    • 单一抽象层级
    • 无参最优,一参数次之,二参数最次,不应超过3参数,否则应引入参数结构或对象
    • 避免将参数作为输出
  • Chapter 4  注释

    • 尽量少用注释,避免过时的注释
    • 如果能用良好的命名来表现意图,就不用注释
    • 如果能用代码来表现意图,就不用注释
    • 良好的注释: 
      • 提供补充信息
      • 解释意图
      • 警告
      • TODO 注释
      • 强调注释
  • Chapter 5  格式

    • 垂直格式:
      • 单个类文件,不超过100行/150行/200行
      • 使用空行分隔方法
      • 自顶向下的方法依赖分布
    • 水平格式
      • 单行不超过80字符/100字符/120字符,屏幕能够全部显示
      • 保持缩进
      • 使用空格,运算符左右使用空格等
      • 显式地突出空循环,避免省略地写为一行
      • 优先遵循团队规定的格式
  • Chapter 6  对象和数据结构

    • 数据结构和对象的对立性:
      • 数据结构以 public 暴露内部属性,不提供访问方法
      • 对象以 private 隐藏内部属性,提供访问方法
      • 数据结构易于增加新方法,同时不影响已有结构。对象反之,易于增加新类,同时不影响已有方法。
      • 数据结构不便于增加新数据结构,因为需要改变每个已有方法。对象反之,不便于增加新方法,因为需要改变每个已有类。
      • Law of demeter:最少知识原则,一个对象应对其他对象有尽量少的了解。类C的 f 方法,应只调用这些方法:
        • 类C的方法
        • f 创造的对象的方法
        • 传递给 f 的参数对象的方法
        • 类C的成员实例变量的方法
  • Chapter 7  错误处理

    • 使用 exception, 避免使用返回的错误码
    • 逐层 throw exception,在最顶层 catch,即定义一个错误传递流
    • 将 try/catch 抽取出来作为独立函数
    • 在需要时定义新的 exception 类
    • 不要返回 null,定义一个 Null 类
    • 不要传递 null
  • Chapter 8  边界

    • 在自己的代码和第三方代码的边界处,使用自己编写的代码适配(适配器),避免将第三方代码直接嵌入自己的代码
    • 测试第三方代码
  • Chapter 9  单元测试

    • TDD
    • 测试代码和生产代码同样重要,但测试代码不一定需要遵循同样的效率和资源限制
    • 保持测试代码的clean,避免过时和冗余等
    • BUILD-OPERATE-CHECK 的测试模板
    • given/when/then 的测试方法命名建议
    • 模板方法模式可能有所帮助
    • 每个测试方法,仅测试一个概念
    • F-I-R-S-T原则
      • Fast,测试效率要高
      • Independent:每个测试应当独立
      • Repeatable:在不同环境下均可运行
      • Self-Validating:应拥有一个boolean的输出,自身直接输出测试是否通过
      • Timely:每个测试应 just before 写在生产代码之前
  • Chapter 10  类

    • 类成员顺序如下,自顶向下
      • public static constants
      • private static constants
      • private instance variables
      • public functions
      • 被 public function  调用的 private functions 紧跟在该 public function 之后,满足自顶向下的阅读顺序
    • 尺寸:类尽可能小,不同于用物理行数衡量方法的尺寸,应该用 responsibilities 衡量类的尺寸。类应保持单一责任。
    • 类应该保持单一责任(SRP),而类名应该描述这一责任。
    • 类名不应超过25个单词,同时避免 if、and、or、but等代表多责任的词,同时少用大范围的含糊的词,如super,manager等。
    • 尽可能提高类的内聚度:尽量使类中的每个成员变量被类方法使用
    • 将大类分隔为很多小类,优化组织性,提高内聚。但也会造成类数量的激增。
    • 依赖倒置原则(DIP),类依赖于抽象,而不是具体实现。降低耦合。
    • 将类中会变化的部分抽象出来,让客户代码依赖于抽象,而不是具体实现。
  • Chapter 11  系统

    • 将系统构造部分,与使用部分解耦
    • 将构造和初始化部分,全部放在main函数中,再在main函数中,将构造完毕的对象,以参数形式传递给具体使用它们的函数。这是一个方法。
    • 工厂方法可能有所帮助。
    • 依赖注入(DI)和控制反转(IoC)机制可能有所帮助。
    • (这一章没怎么看懂)
  • Chapter 12  迭进

    • Kent Beck 认为的“Simple Design”的四条规则。重要性由上而下递减。
      • 运行所有测试
      • 无重复(良好重构)
      • 表现编程者意图
        • 良好命名
        • 保持类和方法尽可能小
        • 遵循公有标准和共同语言,如通用规范、设计模式等
        • 良好的单元测试
      • 最小化类和方法的数量
        • 经过去重、重构等操作之后,类和方法的数量可能激增。因此在此基础上,尽量减少它们的数量。
  • Chapter 13  并发

    • 复杂且不成熟,跳过。
  • Chapter 14  坏味道和启示

    • 注释 Comments

      • C1 不适宜的注释:修改历史、作者、最近修改日志等,都不适宜出现在注释中。注释应该仅保留技术和业务相关的要点。
      • C2 过时的注释
      • C3 冗余的注释:注释是代码的重复,没有提供额外信息
      • C4 写的很烂的注释:认真措辞,不要随意
      • C5 注释起来的代码:没人知道它的重要性和意义,其他人根本无法轻易地改动它。如果可以,直接删除它
    • 环境 Environment

      • E1 构筑环境需要不只一步:做到一键 build 你的项目环境。
      • E2 单元测试需要不只一步:做到一键 test 你的项目的所有单元测试。
    • 方法 Functions

      • F1 太多参数:无参最佳,1参次之,2参再次,3参再次,多余三个参数,则考虑引入参数结构或对象。
      • F2 输出参数:避免改变参数,然后将它作为结果输出。
      • F3 Flag参数:避免使用Flag参数,这意味着这个方法将做不只一件事。
      • F4 Dead方法:无人问津的方法,直接删除它。
    • 通用 General

      • G1 单个源码文件中,出现多种编程语言:解耦、分离他们。
      • G2 明示的行为没有被实现:应该遵循“最低惊异原则”,任何明示而被期待的行为,都应该被正确实现。否则,代码阅读者将会对更多的代码失去信任。
      • G3 边界处的行为都要被准确实现:任何边界条件、角落case、巧合case、异常case的行为,都需要被准确实现。否则,代码阅读者将会对更多的代码失去信任。
      • G4 覆盖安全机制:避免覆盖你使用的框架提供的安全代码机制,如警告等,不要轻易重载、覆盖、取消它们。
      • G5 重复:不仅包括明显重复的代码,还包括重复的设计等。善用模板方法和策略等设计模式。
      • G6 错误/混乱抽象分层:不同抽象层级的隔离应该明确,一个方法应该仅在同一抽象层级上操作。
      • G7 基础类依赖于它们的衍生类:不要让抽象上层依赖于抽象下层,抽象上层应该对抽象下层一无所知。也有例外:比如上层严格控制了下层衍生物的数量等。
      • G8 单个方法/类/模块负责通过多责任:约束尺寸,约束责任,约束信息。
      • G9 Dead Code:避免永远不会执行的代码,直接删除它。
      • G10 垂直分隔:局部变量和方法需要被定义在他们的使用者附近。private function应该被定义在just below他们的首次调用者处。保持自顶向下的阅读顺序。
      • G11 不一致性:相似的行为应该保持相似一直的结构和命名,保持“最低惊异原则”。
      • G12 杂物:无用的变量,无用的方法,无信息的注释,都应该被尽早删除。
      • G13 人为耦合:解耦那些不必要的、不小心造成的耦合关系。
      • G14 位置不当:类中的方法应该尽量只使用此类中的变量和其他方法,如果某方法更多地使用其他类中的变量和方法,那么它可能需要挪动位置了。
      • G15 传递boolean参数:不要将boolean值作为方法参数,这意味着该方法负责不只一件事。
      • G16 含混的意图:代码自身要意图明确。
      • G17 位置不当:一些变量和方法应该正确地放置在它们最被期待的地方。“最低惊异原则”
      • G18 不适当的static:某些方法适合static,有些不适合,正确处理它们。
      • G19 变量意图不明:使用有解释力和变现力的变量,如合适命名等,增强可读性。
      • G20 方法意图不明:使用有变现力的方法名,增强可读性。
      • G21 对算法理解不明
      • G22
      • G23 建议使用多态来代替if/else和switch/case,当后者重复超过1次时,考虑使用多态替换他们。工厂模式可能有所帮助。
      • G24 建议遵循标准惯例
      • G25 建议使用 Named Constants 代替魔数:魔数自身的变现力低,使用具名常量增强表现力。
      • G26 建议当你首次完成系统时,对细节的完成尽可能详细,不要偷懒。
      • G27 良好结构和惯例之间的取舍,前者优先
      • G28 建议封装条件:将if/else和switch/case处的条件式,用独立而良好命名的方法重新表述,使条件处永远只有一行,并且让那个独立的方法的名字,替你解释此处条件是什么。
      • G29 避免否定条件:首先使用肯定条件。
      • G30 方法只做一件事
      • G31 隐藏临时耦合
      • G32 别随意
      • G33 封装边界条件:将边界条件集中、封装,不要让他们散落各处
      • G34 方法只活动在同一层抽象上
      • G35 让配置信息和数据,保持在高层抽象上,不要定义在底层抽象上,通过参数逐层传递它们。
      • G36 避免多级传递:遵守Law of Demeter
    • Java

      • J1 包引入:如果引入了一个package中的超过两个成员,那么直接引入整个包。
      • J2 不要继承常量:不要将常量声明在基类或接口中,然后继承它们。将常量声明在子类中。
      • J3 使用枚举代替一系列常量。
    • 命名 Naming

      • N1 选择有描述力、表现力的名字
      • N2 在命名时体现不同抽象层级
      • N3 如果可能,采用某些标准惯例下的命名
      • N4 明确命名,避免含混用词
      • N5 相关域越大,其命名可以越长
      • N6 避免编码:??
      • N7 不要将方法不会去做的事,体现在其命名上
    • 测试 Tests

      • T1 不充分的测试
      • T2 使用IDE提供的测试覆盖工具
      • T3 不要跳过那么低级的、显而易见的trivial测试
      • T4
      • T5 细心测试边界条件
      • T6 当你发现bug时,正儿八经地测试它
      • T7 测试失败pattern
      • T8
      • T9 测试需要快速