《代码简洁之道–Clean Code》 摘记

第 2 章 有意义的命名

  • 名副其实: 变量、函数或类的名称应该告诉你,它为什么会存在,它做什么事,应该怎么用。如果名称需要注释来补充,那就不算名副其实。
    代码的模糊度:即上下文在代码中未被明确体现的程度。

  • 避免误导: 提防使用不同之处较小的名称。

  • 做有意义的区分: 要区分名称,就要以读者能鉴别不同之处的方式来区分。

  • 使用读得出来的名字。

  • 使用可搜索的名称 : 长名称胜于短名称,搜得到的名称胜于自造编码代写就的名称。单字母名称仅用于端方法中的本地变量。名称长短应与其作用域大小相对应。

  • 避免使用编码 : 不要用类型前缀、特定前缀来标记成员。

  • 避免思维映射 : 聪明程序员和专业程序员之间的区别在于,专业程序员了解,明确是王道

  • 类名 : 类名和对象名应该是名词或名词短语。

  • 方法名 : 方法名应当是动词或动词短语。重载构造器时,使用描述了参数的静态工厂方法名。

  • 每个概念对应一个词 : 给每个抽象概念选一个词,并且一以贯之。

  • 别使用双关语;

  • 使用解决方案领域名称 :

  • 使用源自所涉问题领域的名称;

  • 添加有意义的语境

  • 不要添加没用的语境 : 精确是命名的要点。

取好名字最难的地方在于需要良好的描述技巧和共有文化背景。

第 3 章 函数

  • 短小 : 函数的第一规则是要短小,第二条规则是还要更短小。每个函数都只做一件事,且每个函数都依序把读者带到下一个函数,这就是函数应该达到的短小程度。
    if 语句、else 语句、 while 语句等,其中的代码块应该只有一行,该行大抵是一个函数调用语句。这样不但能保持函数短小,而且,因为块内调用的函数拥有较具说明性的名称,从而增加了文档上的价值。所以,函数的嵌套层级不该多于一层或两层。

  • 只做一件事 : 函数应该只做一件事。编写函数是为了把大一些的概念拆分为另一抽象层上的一序列步骤。只做一件事的函数无法被合理地切分为多个区段。

  • 每个函数一个抽象层级 : 要确保函数只做一件事,函数中的语句都要在同一抽象层级上。
  • switch 语句 : 利用抽象工厂和多态来化解。
  • 使用描述性名的称 : 函数越短小、功能越集中,就越便于取个好名字。命名方式要保持一致,使用于模块名一脉相承的短语、名词和动词给函数命名。
  • 函数参数 : 最理想的参数数量是零个,尽量避免三个删除。参数与函数名处在不同的抽象层级,它要求你了解目前并不特别重要的细节。尽量不要有标识(比如boolean类型的)参数。
  • 无副作用 : 函数最好是无副作用的。输出参数是会被修改的函数的参数;应避免使用输出参数,如果函数必须要修改某种状态,就修改所属对象的状态。
  • 分隔指令与询问 : 函数应该修改某对象的状态(指令),或是返回该对象的有关信息(询问)。两样都做会导致混乱。
  • 使用异常代替返回错误码 : 抽离 try/catch 语句到另外的函数;错误处理就是一件事;使用异常替代错误码,新异常就可以从异常类派生出来,无须重新编译或重新部署。
  • 别重复自己, DRY : 重复可能是软件中一切邪恶的根源。
  • 结构化编程 : 每个函数、函数中的每个代码块都应该有一个入口、一个出口。这个规则对于大函数有明显好处。

第 4 章 注释

什么也比不上放置良好的注释来得有用,什么也不会比乱七八糟的注释更有本事搞乱一个模块,什么也不会比陈旧、提供错误信息的注释更有破坏性。

注释最多是一种必须的恶。

如果有足够的表达力,根本就不需要注释。

第 5 章 格式

代码格式关乎沟通,而沟通是专业开发者的头等大事。

每行展现一个表达式或一个语句,每组代码行展示一条完整的思路。这些思路用空白行区隔开来。

变量声明应尽可能靠近其使用位置。

概念相关:概念相关的代码应该放在一起,相关性越强,彼此之间的距离就该越短。

自上向下展示函数的调用依赖顺序。

第 6 章 对象和数据结构

对象把数据隐藏于抽象之后,曝露操作数据的函数。数据结果曝露其数据,没有提供有意义的函数。

过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数。面向对象代码便于在不改动既有函数的前提下添加新类。

得墨忒尔律(The Law of Demeter)认为,模块不应了解它所操作对象的内部情形。

得墨忒尔律认为,类 C 的方法 f 只应该调用以下对象的方法:

  • C ;
  • 由 f 创建的对象;
  • 作为参数传递给 f 的对象;
  • 由 C 的实体变量持有的对象;
  • 方法不应调用由任何函数返回的对象的方法。

对象曝露行为,隐藏数据,便于添加新对象类型而无需修改既有行为,同时也难以在既有对象中添加新行为。
数据结构曝露数据,没有明显的行为,便于向既有数据结构添加新行为,同时也难以向既有函数添加新数据结构。

第 7 章 错误处理

  • 使用异常而非返回码
  • 先写 try-catch-finally 语句
  • 使用不可控异常 : 使用可控异常,就得在 catch 语句和抛出异常处之间的每个方法签名中声明该异常。这意味着对软件中较低层级的修改,都将波及较高层次的签名。
  • 给出异常发生的环境说明。
  • 依调用者需要定义异常类。
  • 定义常规流程 : 创建一个类或配置一个对象,用来处理特例。这样客户代码就不用应付异常行为了,异常行为被封装到特例对象中。
  • 别返回 null 值;
  • 别传递 null 值;

第 10 章 类

  • 类的组织 : 首先是公共静态常量,私有静态变量,私有实体变量,公共函数;公共行数调用的私有工具函数紧随在该公共函数后面。

  • 类应该短小 :

    • 类的大小以权责(responsibility)多少来衡量。
    • 单一职责原则(SRP)认为类或模块应有且只有一条加以修改的理由。
    • 内聚:类应该只有少量实体变量,类中的每个方法都应该操作一个或多个实体变量;方法操作是实体变量越多,就越黏聚到类上,如果类中的每个实体变量都被每个方法所使用,则该类具有最大的内聚性。
    • 保持内聚性就会得到许多短小的类。
  • 为了修改而组织 : 隔离修改。

依赖倒置原则: Dependency Inversion Principle, DIP 。

第 11 章 系统

11.2 将系统的构造与使用分开

软件系统应将起始过程和起始过程之后的运行逻辑分离开,在起始过程中构建应用对象,也会存在互相缠结的依赖关系。

实现方法:

  • 分解 main :将全部构造过程搬迁到 main 或称之为 main 的模块中,设计系统的其余部分时,假设所有对象都已正确构造和设置。
  • 工厂:
  • 依赖注入:在依赖管理情景中,对象不应负责实体化对自身的依赖,反之,它应当将这份权责移交给其他“有权力”的机制,从而实现控制的反转。因为初始设置是一种全局问题,这种授权机制通常要么是 main 例程,要么是有特定目的的容器

11.3 扩容

与物理系统相比软件系统比较独特,它们的架构都可以递增式地增长,只要我们持续将关注面恰当地切分。软件系统短生命周期的本质使这一切变得可行。

面向方面编程(aspect-oriented programming, AOP),是一种恢复横贯式关注面模块化的普适手段。

在 AOP 中,被称为方面(aspect)的模块构造指明了系统中哪些点的行为会以某种一直的方式被修改,从而支持某种特定的场景。这种声明是用某种简洁的声明火编程机制来实现的。

AOP 有时会与其他技术混淆,例如方法拦截和通过代理做的“封包”。AOP 系统的真正价值在于用简洁和模块化的方式指定系统行为。

11.4 Java 代理

代码量和复杂度是代理的两大弱点,创建简洁代码变得很难。代理也没有提供在系统范围内指定执行点的机制,而那正是真正的 AOP 解决方案所必须的。

11.7 测试驱动系统架构

用 POJO 编写应用程序的领域逻辑,在代码层面与架构关注面分离开,就有困难真正地用测试来驱动架构。

最佳的系统架构由模块化的关注面领域组成,每个关注面均用纯 Java(或其他语言)对象实现。不同的领域之间用最不具有侵害性的方面或类方面工具整合起来。

在所有的抽象层级上,意图都应该清晰可辨。只有在编写 POJO 并使用类方面的机制来无损地组合其他关注面时,这种事情才会发生。

无论是设计系统或单独的模块,别忘了使用大概可工作的最简单方案

第 12 章 迭进

Kent Beck 关于简单设计的四条规则:

  • 运行所有测试;
  • 不可重复;
  • 表达了程序员的意图;
  • 尽可能减少类和方法的数量;
  • 以上规则按其重要程度排列。

12.2 简单设计规则1:运行所有测试

全面测试并持续通过所有测试的系统,就是可测试的系统。只要系统可测试,就会导向保持类短小且目的单一的设计方案。遵循 SRP 的类,测试起来较为简单。测试编写的越多,就越能持续走向编写教易测试的代码。确保系统完全可测试能帮助创建更好的设计。

测试消除了对清理代码就会破坏代码的恐惧。

12.4 不可重复

重复是拥有良好设计系统的大敌。它代表着额外的工作、额外的风险和额外且不必要的复杂度。

“小规模复用”可大量降低系统复杂性。要想实现大规模复用,必须理解如何实现小规模复用。

12.5 表达力

软件项目的主要成本在于长期维护。

做到有表达力的最重要方式却是尝试


欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据