《代码不朽》读书笔记

《代码不朽:编写可维护软件的10大要则》读书笔记。

1 三个基本理论

本书提供了10条可以实现高可维护性的原则。这些原则的理论如下:

理论一:坚持简单的原则最有助于提高可维护性。

理论二:可维护性不是开发完才考虑的事情,而应该是在项目开发的一开始就加以考虑,每个人的贡献都应当计算在内。

理论三:对各个原则的违背会带来不同的影响,有些严重程度甚于其他。一个软件系统越遵循原则,可维护性越高。

2 原则1:编写短小的代码单元

2.1 原则描述

  1. 代码单元的长度应该限制在15行代码以内。
  2. 为此首先不要编写超过15行代码的单元,或者将长的单元分解成多个更短的单元,直到每个单元都不超过15行代码。
  3. 该原则能提高可维护性的原因在于:短小的代码单元易于理解、测试及重用

在java中,代码单元指方法或者构造函数。

2.2 如何使用本原则

2.2.1 重构技巧:提取方法

该重构方法较为简单,不详细描述。当我们将一个代码单元拆分成多个是,有可能会增加总的代码行数。但同时也降低了这个代码单元的长度和复杂度。因此编写可维护代码总是在不断的做权衡,达到最佳效果。

2.2.2 重构技巧:将方法替换为方法对象

参考原则4。

当我们使用“提取方法“的重构技巧,如果提取的代码单元访问了局部变量,虽然可以将局部变量作为参数传递。但有可能导致参数列表过多的问题。则可以尝试使用”将方法替换为方法对象“的技巧。创建一个新的类来代替方法。(参考书18页)。

3 原则2:编写简单的代码单元

3.1 原则描述

  1. 限制每个代码单元分支点的数量不超过4个。
  2. 应该将复杂的代码单元拆分成多个简单的单元,避免多个复杂的单元在一起。
  3. 该原则能提高可维护性的原因在于:分支点越少,代码单元越容易被修改和测试

分支点:在Java中,以下语句和操作符都被认为是分支点:

ifcase?&&, ||whileforcatch

关于书中关于覆盖率的概念,可以查看 代码覆盖率浅谈

3.2 如何使用本原则

3.3.1 处理链式条件语句

链式条件语句:每个条件都是互斥的。例如:switch语句,if…else if… 语句。

【方式一:采用Map数据结构重构】(参考书34页)

【方式二:使用多态来代替条件判断(Replace Conditional with Polymorphism)】(参考书34页)

抽取公共接口,为每个条件定义不同的实现类。

这种方式不好之处是引入了更多的类和代码。

3.3.2 处理嵌套条件语句

【方式:使用卫语句来代替嵌套的条件语句(Replace Nested Conditional with Guard Clauses)】(参考书36页)

卫语句:如果某个条件极其罕见,就应该单独检查该条件,并在该条件为真时立刻从函数中返回,以减少嵌套语句的发生。

4 原则3:不写重复的代码

4.1 原则描述

  1. 不要复制代码。
  2. 你应该编写可重用、通用的代码,并且/或者调用已有的代码。
  3. 该原则能提高可维护性的原因在于:如果复制代码,就需要在多个地方修复bug,这样做不仅低效,而且容易出错。

重复代码/克隆代码的定义:一段至少6行相同的代码。不包括空行和注释行。

重复代码的类型:

  1. 1类克隆:这几行代码必须完全一样(文字上完全相同)。
  2. 2类克隆:在语法上相同,只在空格、注释、标识符名称和字面值不同。但2类克隆不一定是1类克隆。

移除1类克隆对可维护性的提升最大。

1类克隆更容易检测和识别,2类克隆都需要完整的语法分析才能识别。(参考书44页)

4.2 如何使用本原则

【方式一:永远不要复制粘贴已有的代码。】

【方式二:可以使用原则1中所说的“提取方法”的重构技巧解决重复的代码问题。

【方式三:重构技巧:提取父类。】

4.2.1 重构技巧:提取父类

因为二者有一些相同的功能而造成了重复的代码,可以使用“提取父类”的重构技巧,不仅将代码行片段提取出方法,而且提取到原类的一个新的父类中。(参数书47页)

5 原则4:保持代码单元的接口简单

5.1 原则描述

  1. 限制每个代码单元的参数不能超过4个。
  2. 你应该将多个参数提取成对象
  3. 该原则能提高可维护性的原因在于:较少的参数可以让代码单元更容易理解和重用

5.2 如何使用本原则

过长的接口本身不是问题,而是实际问题的一个表现—意味着代码中可能存在着设计不合理的数据模型,或者随意的改动。

【方式一:将多个参数提取成对象】:

将多个参数提取成对象。这些对象通常被称为数据传输对象(DTO)或者参数对象。可以在代码中被频繁的重用。(参考书59页)

如果各个参数无法组合,仍然可以将它们封装成对象,但这个类只能使用一次了。使用原则1中所提到的”将方法替换为方法对象”的重构技巧。将原来的方法,放在新类中。(参考书61页)

【方式二:使用方法重载,提供默认值,简化方法的调用】:(参考书60页)

使用方法重载的方式,重载一个方法,只是参数减少,其他的参数采用默认值。

若第三方库/框架中使用了长参数列表的接口,最好的办法是使用包装类或者适配器对他们进行隔离。

6 原则5:分离模块之间的关注点

6.1 原则描述

  1. 避免形成大型模块,以便达到模块之间的松耦合。
  2. 你应该将不同的职责分给不同的模块,并且隐藏接口内部的实现细节。
  3. 该原则能提高可维护性的原因在于:相比起紧耦合的代码库来说,对松耦合代码库的修改更容易监督和执行。

这里的模块概念,对应java中的类的概念。

6.2 如何使用本原则

本原则会要求保持类的体积尽可能的小。(专注于某一个关注点),并限制外部对该类的调用数量。

6.2.1 根据不同关注点拆分类

为了避免类变大越来越大,必须在类承担超过一个职责时,对类进行拆分。(参考书69页)

6.2.2 隐藏接口背后的特定实现

可以通过隐藏高层接口背后特定、具体的实现细节(继承和接口),来达到松耦合的目的。(参考书70页)

6.2.3 可以使用第三方库、框架来替换自定义代码

通用功能或者工具方法的类通常会导致模块紧耦合的情况。例如StringUtils工具类。可以使用第三方库例如:Apache Commons

7 原则6:架构组件松耦合(不理解)

7.1 原则描述

  1. 顶层组件之间应该做到松耦合。
  2. 你应该尽可能的减少当前模块中需要暴露给(例如,被调用)其他组件中模块的相关方法。
  3. 该原则能提高可维护性的原因在于:独立的组件可以单独进行维护。

模块耦合度关注于单个模块(类)对系统其他部分的暴露程度,而组件耦合度关注的是一个组件中的模块,对其他组件中的模块的暴露程度。

能够提升可维护性的调用分为两种:

  • 内部调用是健康的。内部逻辑对于外部是隐藏起来的。
  • 传出调用也是健康的。把它们要做的任务代理给其他组件。

一个组件的传出调用,就是其他组件的传入调用。

对可维护性有负面影响的调用:

  • 传入调用,为其他组件提供功能。组件内的代码应当尽可能的进行封装,即应当避免来自其他组件的直接调用,。同样,修改传入依赖中的代码,会对其他组件造成很大影响,应降低传入依赖所涉及的代码。
  • 透传代码必须要避免,既接受传入调用,又同时代理给其他组件。

7.2 如何使用本原则

7.2.1 抽象工厂设计模式

(参考书79页)

关于抽象工厂设计模式,可以查看 链接

8 原则7:保持架构组件之间的平衡

8.1 原则描述

  1. 需要平衡代码中顶层组件的数量和体积。
  2. 应该保持源代码中组件的数量接近9,并且这些组件的体积基本一致。
  3. 该原则能提高可维护性的原因在于:平衡的组件可以帮助定位代码,并且允许独立对组件进行维护。

8.2 如何使用本原则

关于组件平衡的两个原则:

  • 顶层系统组件个数在理想状态下应为9,通常来说位于6到12之间。
  • 各个组件的代码量应该大致相当。

对组件的划分应该是自然而然的,而不是刻意要划分成9个组件。

9 原则8:保持小规模代码库

9.1 原则描述

  1. 保持代码库规模尽可能小。
  2. 应该控制代码库增长,并主动减少系统的代码体积。
  3. 该原则能提高可维护性的原因在于:拥有小型的代码,项目和团队是成功的一个因素。

9.2 如何使用本原则

  • 功能层面:
    • 控制需求蔓延。
    • 功能标准化。将功能统一标准化,在程序的行为和交互方面保持一致。可以避免多个地方实现基本相同,但略有区别的功能;有利于重用已有代码。
  • 技术层面:用更少的代码实现相同的功能。
    • 不要复制粘贴代码。
    • 重构已有代码。
    • 使用第三方库和框架。
    • 拆分大型系统:将一个大型系统拆分成多个较小的系统。

10 原则9:自动化开发部署和测试

10.1 原则描述

  1. 对你的代码做自动化测试。
  2. 应该通过使用测试框架来编写自动化测试。
  3. 该原则能提高可维护性的原因在于:自动化测试让开发过程可预测并且能够降低风险。

10.2 如何使用本原则

  • 单元测试的基本原则:
    • 正常情况和特殊情况都要测试。
    • 像维护非测试(生产)代码一样维护测试代码。
    • 编写独立的测试,不依赖于其他测试文件的写入。

11 原则10:编写简洁的代码

11.1 原则描述

  1. 编写简洁的代码。
  2. 不应该在完成开发工作后留下代码坏味道。
  3. 该原则能提高可维护性的原因在于:简洁的代码是可维护的代码。

11.2 如何使用本原则

  • 【不要编写单元级别的代码坏味道】

    即不要编写过长的代码(原则1),不要编写复杂的代码单元(原则2),不要编写长接口的代码(原则4)。

  • 【不要编写不好的注释】

  • 【不要注释代码】

    版本控制系统会永远保留一份旧代码的记录,因此可以很安全的删除。

  • 【不要保留废弃代码】

    废弃代码指的是根本不会被执行或者输出被废弃(代码可能被执行,但没有任何地方使用它的输出)的代码。

    • 废弃代码:方法无法到达的代码。
    • 废弃代码:无用的私有方法,如果私有方法没有被类中的任何代码调用,就是废弃的。
    • 注释中的代码
  • 【不要使用过长的标志符名称】

  • 【不要使用魔术常量】

    魔术常量:代码中没有被清晰定义的数字或者字符串。

  • 【不要使用未正确处理的异常】

    • 捕获一切异常,并且空的cache代码库是不好的实践行为。
    • 捕获特定异常,不应该直接捕获ThrowableExceptionRuntimeException异常。
    • 将特定的异常信息转换成通用的信息展示给用户。
-------------本文结束感谢您的阅读-------------
0%