读万卷书(一):《代码不朽》

【引言】《代码不朽》,书名全称《代码不朽:编写可维护软件的10大要则(Java版)》,作者:【荷】Joost Visser(约斯特·维瑟),英文原版名《Building Maintainable Software》,豆瓣读书评分7.7。(阅读周期: 2018.03.01 - 2018.08.15)


序言

  序言中有一句很好的古语:“上医治未病,中医治欲病,下医治已病”(这么传统的国语风,想必是译者的发挥吧!);用到软件质量管理上,再合适不过了;我们经常说的要以客户为中心,客户最关注的想必也是产品的质量。
  本书陆陆续续到半年之后的某天(2018.08.15),算是草草浏览完毕,真的仅仅是草草浏览,虽然书中说得很多道理都是很基本的,但是想把软件做好,这些原则也是必不可缺的基石和根本。

第1章:简介

软件质量的8个特征

  • 可维护性
  • 功能可适性
  • 性能效率
  • 兼容性
  • 可使用性
  • 可靠性
  • 安全性
  • 可移植性

可维护性基本原则

  • 坚持简单的原则有助于提高可维护性
  • 可维护性不是开发完成后才取考虑的,而应该是在项目开发的一开始就需要考虑,每一个人的贡献都需要计算在内(避免破窗效应)。
  • 对各个原则的违背会带来不同的影响,有些严重程度甚于其他;一个软件系统越遵守原则,可维护性越高。(2-11章便是软件可维护性的十大原则)

第2章:编写短小的代码单元

基本原则

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

动机

  • 短小的代码单元易于测试、分析和重用。

操作

  • 适时的进行代码重构
  • 将方法替换为方法对象(尤其是针对多参数的方法)

第3章:编写简单的代码单元

基本原则

  • 限制每个代码单元分支点的数量不超过4个
  • 考虑将复杂的代码单元拆分成多个简单的单元,避免多个复杂的单元糅合在一起
  • 该原则对可维护性的提高很显而易见,主要是因为分支点越少代码单元越容易被理解、修改和测试

动机

  • 简单的代码单元易于修改和测试

操作

  • if、case、while、switch、for之类的分支嵌套都需要控制好层次
  • 可考虑借用Map或者利用Java语言的多态性来精简链式条件语句
  • 可考虑利用函数抽取或反条件return/break的方式,减少嵌套语句的嵌套层次

第4章:不写重复代码

基本原则

  • 禁止复制代码;禁止复制代码;禁止复制代码;重要的事情说三遍
  • 应编写可重用的、通用的代码;或者是复用已有的代码单元

动机

  • 重复代码的分析和修改都更浪费成本

操作

  • 有超过6行重复的代码或代码块,就必须考虑提取以解决重复性
  • 处理的方式:类的继承、提取出公共工具
  • 善用第三方工具(比如Apache本身有很多工具封装),不要重复造轮子
  • 不要认为重复字符串就不需要重构,实际也是很有必要的(比如sql里面的关键词)

第5章:保持代码单元和接口简单

基本原则

  • 每个方法的参数尽量控制在不超过4个
  • 参数过多时,尽量使用对象封装

动机

  • 短接口更易于理解和重用
  • 短接口的方法更易于修改

操作

  • 必须时刻牢记控制接口参数的数量
  • 对默认值进行方法重载(比如:JDK里的很多集合类,有很多不同的重载构造方法)
  • 单一职责原则,就是一个方法尽量只做一件事,流程主方法负责串联流程,每个方法要做到责任明确

第6章:分离模块之间的关注点

基本原则

  • 避免形成超大型的模块,便于实现模块之间的松耦合
  • 类的职责尽量要单一化,简单明了;不要将不同职责糅合到一个模块,尽量做好职责划分
  • 面向接口,通过接口屏蔽实际实现

动机

  • 小型、松耦合的模块允许开发人员独立进行工作(便于工作划分)
  • 小型、松耦合的模块降低了浏览理解代码的难度
  • 小型、松耦合的模块避免让新人赶到手足无措和焦虑

操作

  • 避免写超大的类,可以考虑根据不同的关注点将一个大类拆分成多个小类
  • 可利用很多第三方库或框架来替换自己写的代码,毕竟它们的稳定性和可靠性是经过验证的(StringUtils、FileUtils等很多不同的Utils)

第7章:架构组件松耦合

基本原则

  • 顶层组件之间应该做到松耦合
  • 尽可能的减少当前模块中需要暴露给(例如:被调用)其他组件中模块的相关代码

动机

  • 低组件依赖允许独立维护,不依赖于整个系统
  • 低组件依赖可以分离维护职责
  • 低组件依赖让测试变得更容易

操作

  • 限制作为组件接口的模块的大小
  • 做更高层次的抽象
  • 避免使用透传调用(避免对其他组件接口模块的直接调用)
  • 注意设计模式的使用(比如:抽象工厂)

第8章:保持架构组件之间的平衡

基本原则

  • 需要平衡代码中顶层组件的数量和体积;也就是要保证组件平衡性
  • 应该保持源代码中的组件数量接近于9(比如:6-12),并且要保证组件的体积基本一致

动机

  • 好的组件平衡能让查找和分析代码更容易
  • 好的组件平衡能隔离维护所带来的影响
  • 好的组件平衡能分离维护职责

操作

  • 确定将功能合成组件的合适原则,不要盲目的合成
  • 明确系统的领域并一直坚持下去

第9章:保持小规模代码库

基本原则

  • 保持代码库的规模尽可能小
  • 控制代码库的增长,并且必要的情况下要主动减少系统的代码体积

动机

  • 以大型代码库为目标的项目易失败
  • 大型代码库的维护难度更高
  • 大型系统会出现更密集的缺陷

操作

  • 控制需求的蔓延
  • 不要复制粘贴代码
  • 适时重构已有代码
  • 使用第三方库和框架

第10章:自动化开发部署和测试

基本原则

  • 需要对你的代码进行自动化测试
  • 尽量通过测试框架来编写测试代码

动机

  • 自动化测试让测试可重复
  • 自动化测试会让开发更有效率
  • 自动化测试让代码行为可预测
  • 测试实际是对被测代码的一个补充文档
  • 编写单元测试用例能让你编写更好的代码

操作

  • Junit
  • 编写单元测试必须严谨(正常、非正常;保持测试的独立性)
  • 保证测试覆盖率

第11章:编写简洁的代码

基本原则

  • 代码必须保持简洁
  • 不应该在完成开发工作后留下代码坏味道(“离开营地时,要让它比来时更干净”)

操作

  • 不要编写单元级别的代码坏味道
  • 不要编写不好的注释
  • 不要注释代码
  • 不要保留废弃代码
  • 不要使用过长的标识符命名
  • 不要使用魔数常量
  • 不要使用未正确处理的异常(禁止吞噬异常);尽量按照特定异常多次捕获;特定异常特定返回

第12章:后续事宜

  • 将前面所有原则变成实践
  • 低层级(代码单元)的原则要优先于高层级(组件)的原则
  • 每个人都需要对自己每次提交的代码的质量负责,个体的优化是整体优化的前提

后记-2019.02.21

  今天大约是写完这篇文档的半年后了,最近有一段时间没怎么写东西了,一来是前段时间比较忙,二来最近多数空闲时间在思考一些方向;今天抽了点小空把当初记录的这篇《代码不朽》的摘录又过了一遍,愈发深切的体会到“大道至简”这句话的深意。把复杂的东西简单化,才是我们作为技术从业者的终极追求吧!
  今天早上看了一个日本作家的关于阅读技巧的书籍,提到了flow式的阅读体验,在此实践了一下,这一次留下的总体印象大体可以概括为以下几个词:短小、简洁、不重复、复用。希望一段时间之后会有一些新的体会吧!

------2019 Lin.C ------