欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《代码整洁之道读书笔记》

程序员文章站 2022-04-27 08:05:01
...

第十三章《并发编程》感悟(2019.05.29)

为什么要并发

1.并发是一种解耦策略,它帮助我们把做什么(目的)和何时(时机)做分解开

2.解耦目的与时机能明显地改进应用程序的吞吐量和结构

3.单线程程序许多时间花在等待web套接字I/O结束上面,通过采用同时访问多个站点的多线程算法,就能改进性能

常见的迷思和误解
  • 并发总能改进性能:只在多个线程或处理器之间能分享大量等待时间的时候管用

  • 编写并发程序无需修改设计:可能与单线程系统的设计极不相同

  • 在采用web或ejb容器时,理解并发问题并不重要

有关编写并发软件的中肯的说法
  • 并发会在性能和编写额外代码上增加一些开销

  • 正确的并发是复杂的,即使对于简单的问题也是如此

  • 并发缺陷并非总能重现,所以常被看做偶发事件而忽略,未被当做真的缺陷看待

  • 并发常常需要对设计策略的根本性修改

并发防御原则

1.单一权责原则

2.限制数据作用域

3.使用数据副本

4.线程应尽可能独立

了解Java库
  • 使用类库提供的线程安全群集

  • 使用executor框架(executor framework)执行无关任务

  • 尽可能使用非锁定解决方案

  • 有几个类并不是线程安全的

了解执行模型
警惕同步方法之间的依赖
保持同步区域微小
很维编写正确的关闭代码

1.平静关闭很难做到,常见问题与死锁有关,线程一直等待永远不会到来的信号

2.建议:尽早考虑关闭问题,尽早令其工作正常

测试线程代码

1.建议:编写有潜力曝露问题的测试,在不同的编程配置、系统配置和负载条件下频繁运行。如果测试失败,跟踪错误。别因为后来测试通过了后来的运行就忽略失败

2.将伪失败看作可能的线程问题:线程代码导致“不可能失败的”失败,不要将系统错误归咎于偶发事件

3.先使非线程代码可工作:不要同时追踪非线程缺陷和线程缺陷,确保代码在线程之外可工作

4.编写可插拔的线程代码,能在不同的配置环境下运行

5.编写可调整的线程代码:允许线程依据吞吐量和系统使用率自我调整

6.运行多于处理器数量的线程:任务交换越频繁,越有可能找到错过临界区域导致死锁的代码

7.在不同平台上运行:尽早并经常地在所有目标平台上运行线程代码

8.装置试错代码:增加对Object.wait()、Object.sleep()、Object.yield()、Object.priority()等方法的调用,改变代码执行顺序,硬编码或自动化

第十一,二章感悟(2019.05.29)

复杂要人命。它消磨开发者的生命,让产品难以规划、构建和测试。

将构造和使用分开的方法:

(1)分解main,将系统中的全部构造过程搬迁到main或者main模块中:main函数创建对象,再将对象传递给应用程序,应用程序只管使用,对构造一无所知;

(2)如果应用程序需要负责确定何时创建对象,可以创建抽象工厂,让应用程序控制实体创建的时机;

(3)依赖注入,控制反转IoC是依赖管理的手段,它将应用需要的依赖对象的创建权责从对象中拿出来,放在一个专注于此事的对象中,并通过依赖注入(赋值器)将依赖对象传递给应用;

扩容:

面向方面编程(AOP),Java中三种方面和类似方面的机制:代理,纯AOP框架,AspectJ。

(1)java代理:适用于简单情况,如在单独对象或类中包装方法调用。代码量和复杂度是代理的两大弱点。

(2)纯Java AOP框架,如Spring AOP、JBoss AOP

(3)AspectJ:提供将方面作为模块构造处理支持的Java扩展

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

拥有模块化关注面的POJO系统提供的敏捷能力,允许我们基于最新的知识做出优化的、时机刚好的决策。决策的复杂性也降低了。

领域特定语言(DSL)允许所有抽象层级和应用程序中的所有领域,从高级策略到底层细节,使用POJO来表达。

跌进

1.简单设计规则

(1)运行所有测试

不可测试的系统不可验证,不可验证的系统,绝不能部署。

(2)不可重复

通过抽取或是模板方法整合重复代码。

(3)表达力

选用好的名称来表达。

(4)尽可能少的类

第十章《类》感悟(2019.05.28)

类的组织

遵循标准的JAVA约定,类应该从一组变量列表开始。变量顺序:公共静态常量,私有静态变量,私有实体变量。很少有公共变量。公共函数应该在变量列表后面。公共函数调用的私有工具函数紧随在该公共函数的后面。

类应该短小

类应该短小
类的名称应该描述其权责,类名正是判断类的长度的第一个手段。如果无法为某个类命以精确的名称,这个类大概就太长了。类名越含混,该类越有可能拥有过多的权责。系统应该由许多短小的类而不是少量巨大的类组成。每个小类封装一个权责,只有一个修改的原因,并与少数其他类一起协同成期望的系统行为。

内聚

内聚性高:类中的方法和变量相互依赖、互相结合成一个逻辑整体。

当类丧失了内聚性,就需要拆分它。将大函数拆分为许多小函数,往往也是将类拆分为许多个小类的时机。程序会更有组织,也会拥有更为透明的结构。

为了修改而组织

在整洁的系统中,对类进行组织,以降低修改的风险(通过扩展而非修改现有的代码来添加新的特性)。

隔离修改:遵循依赖倒置原则(DIP),应该依赖于抽象而非具体细节。

第九章《单元测试》感悟(2019.05.27)

TDD三定律
  • 定律一 在编写不能通过的单元测试前,不可编写生成代码。
  • 定律二 只可编写刚好无法通过的单元测试,不能编译也不算通过。
  • 定律三 只可编写刚好足以通过当前失败测试的生成代码。
保持测试整洁。

作者这里遵循了重要的事情说三遍的原则:可读性,可读性,可读性。如何做到可读,那就是要保证测试代码同其他代码一样,明确,简洁,足具表达力,这也是这本书一直强调的事情。
测试代码和生产代码一样重要。需要被思考,设计和照料。应该和生产代码一样整洁。

每个测试一个断言

在尽可能减少每个概念的断言数量的同时,最好能做到每个测试函数中只测试一个概念。

F.I.R.S.T原则。
  • 快速(Fast) 测试应该够快。
  • 独立(Independent) 测试应该相互独立。
  • 可重复(Repeatable) 测试应当可在任何环境中重复通过。
  • 自足验证(Self-Validating) 测试应该有布尔值输出。
  • 及时(Timely) 测试应及时编写。

第八章《边界》感悟(2019.05.26)

  • 使用第三方代码:使用第三方代码时,如果有边界接口,可将其保留在类或近亲中,避免从公共API中返回边界接口,或者将其边界接口作为参数传给公共API.

  • 浏览和学习边界:在利用第三方程序包时,没有测试第三方代码的职责,但为要使用的第三方代码编写测试,可能最符合我们的利益。不要在生成代码中实验新东西,而是编写测试来遍览和理解第三方代码。

  • 学习性测试的好处不只是免费:学习性测试是一种精确试验,帮助我们增进对api的理解。当第三方程序包发布了新版本,我们可以运行学习性测验,看看程序包的行为有没有改变。学习性测试确保第三方程序包按照我们想要的方式工作。一旦整合进来,就不能保证第三方代码总与我们的需要兼容。如果第三方程序包的修改与测试不兼容,我们也能马上发现。

  • 整洁的边界:在使用我们控制不了的代码时,必须加倍小心,确保未来的修改代价不会太大。边界上的代码需要清晰的分隔和定义了期望的测试。

第六,七章感悟(2019.05.25)

数据抽象

隐藏实现关乎抽象,类并不简单地取值器和赋值器将变量推向外间,而是暴露抽象接口,以便用户无需了解数据的实现就能擦做数据本体。

数据、对象的反对称性

对象把数据隐藏于抽象之后,暴露操作数据的函数。数据结构暴露其数据,没有提供有意义的函数。回头再读一遍,留意这两种定义的本质。他们是对立的,这种差异貌似渺小,但却有深远的意义。对象与数据结构的二分原理:

  • 过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数。面向对象代码便于在不改动既有函数的前提下添加新类。
  • 反过来讲也说得通: 过程式代码难以添加新的数据结构,因为必须修改所有函数。面向对象代码难以添加新函数,因为必须修改所有类。
迪米特法则

模块不应了解它所操作对象的内部情形。对象隐藏数据,暴露操作。者意味着对象不应通过存取其暴露其内部结构,因为这样更像是暴露而非隐藏其内部结构。

数据传送对象

最为精练的数据结构,是一个只有公共变量,没有函数的类。这种数据结构有时被称为数据传送对象,或DTO。

小结

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

错误处理

错误处理很重要,但如果它搞乱了代码逻辑,就是错误的做法。

(1)使用异常而非返回码;

(2)在编写可能抛出异常的代码时,先写try-Catch-Finally语句;

(3)使用不可控异常:C使用可控异常的代价是:违反“开放/闭合原则”。对于一般性 应用开发,其依赖成本要高于收益;

(4)给出异常发生的环境说明:应创建信息充分的错误消息,并和异常一起传递出去,以便判断错误的来源和处所;

(5)依调用者需要定义异常类(看异常如何被捕获):如打包调用API确保返回通用异常类型;

(6)定义常规流程:创建一个类或配置一个对象,用来处理特例;

(7)别返回null值;

(8)别传入null值:在大多数编程语言中,没有良好的方法能对付由调用者意外传入的null值。恰当的做法是,禁止传入null值。

第五章《格式》感悟(2019.05.24)

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

垂直格式

阅读代码都是从上往下,从左往右读的.在一个类中,在封包声明,导入声明,和每个函数之前都应该使用一个空白行来隔开.这可以给阅读带来愉悦的感受.
空白行隔开了概念,每个空白行都是一条线索,标示出一个新的独立的概念,阅读代码的时候,我们的目光总是容易停留在空白行的前一行或后一行.

  • 变量声明 :变量声明应该尽量靠近其使用位置.类变量应该声明在类的顶部.
  • 相关函数:某函数A调用了函数B,应该尽量把他们放到一起,让A位于B的上方.
  • 概念相关:概念相关的代码应该放到一起,相关性越强,他们之间的距离就应该越短.

横向格式

一行代码应该多宽?应当遵循无需拖动滚动条到右边的原则,每行代码控制在120个字符以内是良好的风格.

个人风格要与团队风格一致

第四章《注释》感悟(2019.05.23)

注释不能美化糟糕的代码:如果能用代码表达清楚,尽量不要用注释。注释只是在弥补我们在用代码表达意图时遭遇的失败。带有少量注释的整洁而又表达力的代码,比带有大力量注释的零碎而复杂的代码像样的多。与其花时间编写注释糟糕的代码,不如花时间让代码变得更加的整洁。

  • 好的注释:法律信息,提供信息的注释,对意图的解释,阐释,警示,TODO注释(推荐:提醒我们未完成的功能),放大,公共API中的Javadoc
  • 坏的注释:喃喃自语,多余的注释,误导性的注释,循规式注释(利用工具将生成的类和函数注释导致废话连篇),日志式注释(这种冗长的记录只会让模块变得凌乱不堪,应当全部删除),废话注释,可怕的废话,位置标记,括号后面的注释,归属与署名,注释掉的代码,HTML注释,非本地信息,信息过多,不明显的联系,函数头,非公共代码中的Javadoc。

第三章《函数》感悟(2019.05.22)

  • 函数的第一规则是要短小,第二条规则还是要更 短小。
  • 函数应该做一件事。只做这件事。做好这件事。
  • 向函数传入布尔值简直就是骇人听闻的做法。这样做方法签名会立刻变得复杂起来,大声宣布本函数不止做一件事。如果标识为true将会这样做,如果标识为false则会那样做。我们应该把标识为true和false这两种情况写到两个函数中,这样逻辑更清晰.
  • 使用描述性的名称:因为他较好的描述了函数做的事。不要害怕长名字,不要害怕花时间取名字,命名方式要保持一致。
  • 最理想的参数数量是零个,其次是一个,如果函数需要两个、三个或三个以上参数,就说明其中一些参数应该被封装为类了。
  • 无副作用:副作用是一种谎言,函数承诺只做一件事,但是会做其他被藏起来的事。
  • 分割指令与询问:函数要么做什么事,要么回答什么事,但二者不可得兼。函数应该修改某对象的状态,或是返回该对象的有关信息。真正的解决方案是把指令与询问分隔开来,防止混淆的发生。
  • 使用异常代替返回错误码。
  • 别重复自己:重复可能是软件中一切邪恶的根源。

总之:把系统当作故事讲,不是当作程序写。

第二章《有意义的命名》感悟(2019.05.21)

  1. 名副其实:命名要名副其实,不需要用注释来说明就表达出其功能作用。
  2. 避免误导:避免留下掩藏代码本意的错误线索,应当避免使用与本意相悖的词。
  3. 做有意义的区分:废话都是冗余的。
  4. 使用读得出来的名称:如果名称读不出来,讨论的时候就会像个傻鸟。
  5. 使用可搜索的名称:如果常量是个长数字,又被别人错改过,就会逃过搜索,从而造成错误。长名称胜于短名称。
  6. 避免使用编码
# 以前觉得这样命名接口没毛病,一看就知道是接口,读完此文才知道:I被滥用到说好听点是干扰,根本是废话
public interface IUserService {}
  1. 避免思维映射:明确是王道,专业的程序员善用其能,编写其他人能理解的代码。
  2. 类名:类名和对象应该是名称或者名词短语,不应当是动词。
  3. 方法名: 应当是动词或者动词短语。
  4. 每个概念对应一个词:给每个抽象概念选一个词,并且一以贯之。
  5. 别用双关:避免将同意单词用于不同的目的。
  6. 使用解决方案领域的名称:技术性的名称通常是最靠谱的做法。
  7. 添加有意义的语境,不要添加没用的语境。
    以上规则,多多注意,提高代码的可读性。

第一章《整洁的代码》感悟(2019.05.20)

糟糕的代码如同沼泽一般,难于逾越,不仅会毁掉一个团队,更可能会毁掉一个公司。因为勒布朗法则:稍后等于永不。故不要想着回头来优化代码,要先设计好,编写的代码经调整优化测试后方可提交。要有专业的程序员素养和态度。做一个“有代码感”的程序员,从混乱中看出其他的可能与变化,选出最佳方案,指导我们制订修改行动计划,按图索骥。
整洁的代码读起来简单令人愉悦,只做好一件事。每个函数,每个类和每个模块都全神贯注于一事,不受四周细节的干扰和污染。果断决绝,没有不必要的细节。在意自己的代码,对自己的代码负责。学习他人的优点,不要故步自封。不断学习,不断实践,方可做到“让营地比你来时更干净”。

相关标签: 读书笔记