Clean Code 总结

为什么要看这本书

我们无法舍弃代码的编写,因为代码是需求细节的实现,而有的细节是无法抽象的。所以就更加体现了好代码的重要性,因为混乱的代码,只会让你疲于维护。 在开始之初,就别抱着“将就”,“后面再改”,“先这样吧”的想法

因为 —稍后等于永不

第一章:整洁的意义

整洁的代码具体体现在

  • 1.有单元测试和验收测试
  • 2.使用有意义的命名
  • 3.它只提供一种而非多种做一件事情的途径 (单一原则)
  • 4.它只有尽量少的依赖关系,并且要明确的定义和提供清晰,尽量少的API
  • 5.代码清晰的表达含义
  • 6.没有重复的代码

第二章:命名

起好名字需要良好的描述技巧和共有文化背景,别让名称阻碍你前进的步伐

1.名副其实的命名

如果名称需要注释来补充,那就不算名副其实。命名要明确,不可模糊定义

2.避免误导

程序员必须避免留下掩藏代码本意的错误线索,应当避免使用与本意相悖的词。 提防使用不同之处较小的词,因为不好区分,后面会花费很多时间在上面

3.做有意义的区分

别因为编译器的需要而去做一些误导和没有意义或者无法区分出意思的命名。 废话都是冗余的,要区分名称,就要以读者能鉴别不同之处的方式来区分

4.使用读得出来的名称

名称读得出来,会更加有利于团队讨论,因为编程本就是一种社会活动

5.使用可搜索的名称

长名称胜于断名称,搜得到的名称胜于用自造代码代写就的名称

6.避免使用编码,消除前缀的需要

编码已经太多,无谓再自找麻烦,因为一个是增加了解码的负担,另一个是增加了理解的负担,增加了可读性的难度。

代码读得越多,眼中就越没有前缀。所以要消除前缀的需要

7.类名+方法名+变量名

类名应该是名词而不是动词。 方法名应当是动词或动词短语。变量名添加语境。 言到意到,意到言到

8.别用双关语

避免将同一单词用于不同目的,同一术语用于不同概念,遵循“一词一义”规则

9.使用解决方案领域名称 还是 使用问题领域名称

优先给这些事起个计算机领域内技术性的名称,eg:JobQueue 。 如果不能用计算机领域熟悉的术语来命名,就根据问题所涉领域而来的名称。 最主要是哪一个更贴近

第三章:函数

一开始的函数代码可能都是冗长而复杂的,我们通过不断打磨, 分解函数,修改名称,消除重复。缩短和重新安置方法来使我们的函数更加精确而清晰的讲述系统的故事

1.短小且只做一件事
要判断函数是否不止做了一件事,还有一个方法,就是看它能否再拆出一个函数。让代码拥有自顶向下的阅读顺序

2.switch 语句
每个switch都埋藏在较低的抽象层级,而且永不重复

3.函数命名
别害怕长名称。长而具有描述性的名称,要比短而令人费解的名称好。 命名方式要与模块名风格保持一致

函数和参数应当形成一种非常良好的动词/名词对形式 eg: writeField(name)

4.函数参数
有足够的理由,才能用多参数函数。 参数带有太多概念性,当参数与函数名处在不同的抽象层级,它要求你了解目前并不特别重要的细节。如果函数参数需要3个以上参数,需要把其中一些参数封装为类

5.输出参数
普遍而言,应避免使用输出参数。如果函数必须要修改某种状态,就修改所属对象的状态吧

6.分隔指令与询问
函数应该修改某对象的状态,或是返回该对象的有关信息。如果两样都干,常会导致混乱

7.使用异常代替错误码
从指令式函数中返回错误码略违反略指令与询问分割的规则

8.消除重复
模块的可读性因为重复的消除而得到了提升。许多原则与实践规则都是为控制与消除重复而创建

第四章:注释

当我们的代码能完整清晰的表达我们意图的时候,也许根本不需要注释。注释的恰当用法是弥补我们在用代码表达意图时遭遇的失败

不准确的注释要比没注释糟糕得多

尽可能的用代码来阐述行为

注释并不能美化糟糕的代码,我们最好的做法是把代码弄干净。应该尽可能的用代码来阐述,而不是注释

好注释:

  • 提供有用的信息
  • 对意图的解释,
  • 对参数或返回值的阐释,
  • 对方法的警示,
  • 放大不合理之物的重要性。
  • 要及时删除不再使用的TODO注释
  • 用于描述良好的公共API

坏注释:

  • 因过程需要就添加注释 (喃喃自语)
  • 多余的注释,不能比代码本身提供更多的信息
  • 误导性注释
  • 循规式注释
  • 日志式注释
  • 废话注释
  • 能用函数或变量时就别用注释
  • 没必要用归属与署名搞脏代码
  • 注释掉的代码及时删除
  • HTML注释
  • 非本地信息
  • 注释信息过多
  • 不明显的联系
  • 非公共代码的JAVADoc

第五章:格式

代码格式很重要,代码格式关乎沟通,而沟通是开发者的头等大事 。希望为代码的整洁、一致及所感知到的对细节的关注而震惊

垂直方向:

  • 方法内变量:声明应尽可能的靠近其使用位置
  • 实体变量:应该在类的顶部声明
  • 相关函数:若某个函数调用了另外一个,应该把他们放到一起,而且调用者应该尽可能放在被调用者上面
  • 概念相关:概念相关的代码应该放到一起。代码的相关性越强,彼此之间的距离就越短

横向格式:

  • 应该尽力保持代码行短小
  • 水平方向上的区隔与靠近
  • 缩进
  • 尽量不用空范围语句体,如果无法避免,就用括号包起来

团队规则:

在团队中工作,一组开发者应当认同一种格式风格,并且一以贯之

第六章:对象和数据结构

数据抽象:

  • 隐藏实现并非只是在变量之间放上一个函数层那么简单。隐藏实现关乎抽象!类并不简单地用setter 和 getter
    将其变量推向外界,而是暴露抽象接口,以便用户无需了解数据的实现就能操作数据本体。
  • 随意乱加setter 和 getter 是最坏的选择

数据、对象和反对称性:

  • 对象:对象把数据隐藏于抽象之后,暴露操作数据的函数
  • 数据结构:数据结构暴露其数据,没有提供有意义的函数
  • 对象与数据结构之间的二分原理:
    过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数;面向对象代码便于在不改动既有函数的前提下添加新类 。 反过来:
    过程式代码难以添加新数据结构,因为必须修改所有函数;面向对象代码难以添加新函数,因为必须修改所有类
  • 不必处处皆面向对象,在一些情况下,过程式代码和数据结构就更适合

得墨式耳律(LoD,迪米特法则)

模块不应该了解它所操作对象的内部情形,方法不应调用任何函数返回的对象的方法。换言之,只跟朋友说话,不与陌生人谈话.

对象暴露行为,隐藏数据,便于添加新对象类型而无须修改既有行为,同时难以在既有对象中添加新行为;

数据结构暴露数据,没有明显的行为,便于向既有数据结构添加新行为,同时难以向既有函数添加新数据结构

第七章:错误处理

当错误出现时,程序员有责任确保代码照常工作,但如果错误处理搞乱了代码逻辑,就是错误的做法。

整洁代码是可读的,但也要强固。可读与强固并不冲突。如果将错误处理隔离看待,独立于主要逻辑之外,就能写出强固而整洁的代码

  • 使用异常而非返回码。让逻辑不被错误处理搞乱
  • 先写try-catch-finally语句。先构造try代码块的事务范围,帮助维护该范围的事务特征
  • 使用未检异常。已检异常违反了开放/闭合原则:得在catch语句和抛出异常处之间的每个方法签名中声明该异常。 选择:
    如果编写的是一套关键代码库,则已检异常有时会有用,因为你必须捕获异常。但对于一般的应用开发,其依赖成本高于收益
  • 给出异常发生的环境说明
  • 依调用者需要定义异常类。 可打包第三方API的异常,降低对它的依赖
  • 定义常规流程。 特例模式:创建一个类或配置一个对象用来处理特例,异常行为被封装到特例对象中
  • 别返回null值
  • 别传递null值

第八章:边界

  • 使用第三方代码。避免从公共API中返回边界接口,或将边界接口作为参数传递给公共API
  • 浏览和学习边界。 不要在生产代码中试验新东西,而是编写测试来遍览和理解第三方代码(学习性测试)
  • 学习log4j
  • 使用尚不存在的代码–已知和未知分隔开的边界。 可使用adapter模式等来进行转换
  • 整洁的边界。 应该避免我们的代码过多的了解第三方代码中的特定信息,依靠你能控制的东西

学习性测试:

不要在生产代码中试验新东西,而是编写测试来遍览和理解第三方代码(学习性测试)

  • 精确试验,增进对API对理解
  • 不光免费,投资上的正向回报。 (发布新版本即可运行学习性测试,进行检验)
  • 确保第三方程序包按照我们想要的方式工作
  • 调用方式一致的输出测试来支持整洁的边界

第九章:单元测试

TDD三定律

  • 第一定律:在编写不能通过的单元测试前,不可编写生产代码
  • 第二定律:只可编写刚好无法通过的单元测试,不能编译也算不通过
  • 第三定律:只可编写刚好足以通过当前失败测试的生产代码

保持测试代码的整洁

  • 好处:能尽可能地保持设计和架构的整洁。测试使改动变得可能
  • 测试代码和生产代码一样重要,需要被思考,被设计和被照料,应该像生产代码一般保持整洁
  • 要素:可读性,可读性和可读性。 如果达到可读:明确,简洁,并有足够的表达力
  • 构造-操作-检验(BUILD-OPERATE-CHECK)模式。 构造测试数据–操作测试数据–部分检验
  • 面向特定领域的测试语言
  • 双重标准 (不必考虑计算机内存资源等情况)

每个测试一个断言

  • 每个测试中都断言数量应该最小化
  • 每个测试函数只测试一个概念

整洁测试的五条准则: F.I.R.S.T

  • 快速(Fast) : 测试应该能快速运行
  • 独立(Independent):测试应该相互独立,某个测试不应为下一个测试设定条件
  • 可重复(Repeatable):测试应当在任何环境中可重复通过
  • 自足验证(Self-Validating):测试应该有布尔值输出,无论成功还是失败
  • 及时(Timely):测试应及时编写

第十章:类

JAVA约定: 公共静态常量–》私有静态常量–》私有实体变量–》公共函数–》公共函数调用的私有工具函数紧随在该公共函数后面。 符合自上向下原则

类应该短小

类的名称应当描述其权责

  • 单一职责原则(类或模块应该有且只有一条加以修改的理由)
  • 内聚。内聚高意味着类中的方法和变量互相依赖、互相结合成一个逻辑整体
  • 保持内聚性就会得到许多短小的类

OCP原则(开放闭合原则)

第十一章:系统

软件系统应将起始过程和起始过程之后的运行时逻辑分离开,在起始过程中构建应用对象,也会存在互相缠结的依赖关系。 使用大概可开展工作的最简单方案

第十二章:迭进

  • 运行所有测试;
  • 不可重复
  • 表达了程序员的意图
  • 尽可能减少类和方法的数量

第十三章:并发编程

为什么要并发

  • 解耦策略:它帮助我们把做什么(目的) 和 何时做(时机)分解开,在单线程中,目的与时机紧密耦合
  • 解耦好处:明显地改进应用程序的吞吐量和结构,从结构的角度看,让应用程序看起来更像是许多台共同协作的计算机,而不是一个大循环,系统因此更被易与理解
  • 其它并发动机:对系统的响应时间和吞吐量有要求

并发误解

  • 并发总能改进性能。 并发有时能改进性能,但只在多个线程或处理器之间能分享大量等待时间的时候管用。事情没那么简单
  • 编写并发程序无须修改设计。 并发算法的设计有可能与单线程系统的设计极不相同。目的与时机的解耦往往会对系统结构产生巨大影响
  • 在采用WEB或EJB容器的时候,理解并发问题并不重要。 实际上,应最好了解容器在做什么

并发中肯说法

  • 并发会在性能和编写额外代码上增加一些开销;
  • 正确的并发是复杂的,即便对于简单的问题也是如此
  • 并发缺陷并非总能重现,所以常被看作偶发事件而忽略,未被当作真的缺陷看待
  • 并发常常需要对设计策略做根本性修改

并发防御原则

  • 单一权责原则。 分离并发相关代码与其它代码
  • 推论: 限制数据作用域。谨记数据封装;严格限制对可能被共享的数据的访问
  • 推论:使用数据副本。从开始就避免共享数据,或者复制对象并以只读方式对待
  • 推论:线程应尽可能地独立。让每个线程独立存在,而不与其它线程共享数据。 尝试将数据分解为可被独立线程(可能在不同处理器上)操作的独立子集

并发相关包

  • java.util.concurrent(主要包括线程池相关类(Executors)、阻塞集合类(BlockingQueue)、并发Map类(ConcurrentHashMap)等)
  • java.util.concurrent.atomic(原子类:AtomicInteger、AtomicIntegerArray、AtomicLong等)
  • java.util.concurrent.locks(锁相关的类:ReentrantLock、Condition、ReentrantLock、ReentrantReadWriteLock等)

执行模型

  • 生产者-消费之模型:一个或多个生产者线程创建某些工作,并置于缓存或队列中;一个或多个消费者从队列中获取并完成这些工作
  • 读者-坐着模型:作者主要为读者线程提供信息源;挑战是平衡读者线程和坐着线程的需求,提供合理的吞吐量,避免线程饥饿
  • 宴席模型:宴席上左右每个人左右都放了一把叉子,吃饭需要两把叉子,吃饱了放下叉子;如果旁边的叉子被其他人使用,只能等到其他人吃饱了放下叉子才能吃饭

第十四章:逐步改进

小步幅修改和保证测试通过,意味着你会不断移动各种东西,重构有点像解魔方,需要经过许多小步骤,才能达到较大目标。每一步都是下一步的基础

代码能够工作还不够,应保持代码持续整洁和简单,永不让“腐败”有机会开始

后面的章节

后面的内容大多是以代码为主,目的是让读者能够通过实际的案列加深对之前理论知识的理解和运用,认真领悟后,会发现,刚开始的代码或许都不是那么完美,都是通过后续的加工和优化,使之逐渐完美,虽然会花不少的时间和精力,但结果是值得的。

总结

从书中get到了很多小技巧以及开发中的一些规范。开发中以前不注重的坏的小细节,都在整体中得到放大,给整体糟糕的可读性和整洁性添砖加瓦。

改变最好的时候是以前,其次是现在。 慢慢的学以致用,把小规范套用起来,有的地方一些 ”原则“ 理解可能不是很透彻,但编程本就不是一蹴而就的事情。 在实践中继续理解吧

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值