《代码整洁之道》读书笔记(下)
全书一共400多页,一共17章,第十三章讲并发,并且在附录A中有对并发的补充,第十四到十六章是一些Java代码的案例,第十七章相当于一个总结。本次写读书笔记主要涵盖前十二章的内容,由于篇幅分为上下两篇。本篇为下,个别章节因为能力有限,没有完全弄懂,就先空着了。
第七章 错误处理
错误处理简单来说就是当软件出现错误时还能正常工作。错误处理很重要,但不能打乱的原本的代码逻辑。
使用异常处理而非返回码,底层往上抛,最上层集中处理。这点在第三章函数中也提到过,之所以看到有的地方是使用错误返回码,是因为早期的一些语言没有异常处理机制。现在的语言基本都有异常处理机制。
异常的信息应该足够充分(包含出错的位置以及原因)。
不要在catch块中去实现业务逻辑,就是说当出现异常的时候一定要抛出,而不要改变状态或是做其他一些操作,这样会留下很多陷进。
底层的方法不要返回Null值,否则在调用时会添加很多的判断,可以抛出异常或返回特例对象,特例对象是指返回一个函数返回值类型的空对象。
不要传递Null值。
第八章 边界
无
第九章 单元测试
我工作以来所经历的公司中都很少使用单元测试,以致于我现在对单元测试这方面还不是特别熟悉,只是在自己的个人项目中写过一些单元测试的代码。在DotNet平台下可以使用VS自带的单元测试功能或是NUnit。
现在有一种编程的方法叫TDD(测试驱动开发),意思是先写单元测试,然后写对应的代码,通过修改调试让写的代码通过单元测试。使用TDD,会使测试覆盖所有的代码,测试代码和生产代码的比例有可能会达到1:1 ,所以也会带来成本的问题。TDD三定律:
- 在编写不能通过的单元测试前,不可以编写生产代码;
- 只有编写刚好无法通过的单元测试,不能编译也算不通过;
- 只可编写刚好足以通过当前失败测试的生产代码。
测试代码和生产代码一样的重要,也需要保持整洁。测试代码要随着生产代码的修改而修改,否则只会产生大量无用的测试代码,而且也会给生产代码的修改带来风险。
单元测试的好处:
- 有了测试不用担心对代码的修改;
- 有了测试可以毫无顾虑的去改进架构和设计;
整洁测试的三要素 :可读性、可读性、可读性,测试中的可读性甚至比生成代码中的可读性还要重要。要做到高可读性,测试代码需要满足:明确、简洁和足够的表达力。
每个测试都可以拆分为三个环节:构造测试数据、操作测试数据、检验操作是否达到预期结果。
双重标准:指的是在测试环境中和生产环境中有些条件不必完全一致。生产环境中有时要考虑内存、cpu等性能问题,而在测试环境中不必做这些限制。
每个测试一个断言,不必完全纠结,但单个测试断言数应该最小化。
每个测试函数只测试一个概念,还是单一职责的问题。
整洁的测试代码要满足“FIRST”原则
- 快速(Fast):测试运行应该够快,如果运行很慢就不会想频繁去运行它,就会导致不能及时发现问题。
- 独立(Independent):测试应相互独立,某个测试不应成为下个测试的设定条件,应该可以单独运行每个测试。测试如果相互依赖,会导致一连串的测试失败,查找问题比较困难。
- 可重复(Repeatable):可以在任何环境中重复通过。
- 自足验证(Self-Validating):测试应该有布尔值输出,无论是成功还是失败。
- 及时(Timely)测试应及时编写,单元测试应该在使其通过的生产代码编写之前编写。按这种要求及时TDD开发了,但在实际工作中并不是总能遇到TDD开发的团队。
第十章 类
类通常由变量、属性和方法组成。按照书中所讲的Java的约定,类应该由一组变量开始,如果有静态公共常量,应该放在前面,然后是私有静态变量和私有实体变量。公共函数跟在变量之后,一些供公共函数调用的私有工具函数在公共函数之后。
和函数一样,类也应该要尽可能的短小。但和函数不同不是以代码行数来权衡,而是以职责。如果无法准确的为某个类命名,则有可能是该类的职责过多。
单一职责原则(SRP):类或模块应该有且只有一条加以修改的理由。
在实际的工作中很多开发人员往往不会思考这么多,他们只想着让代码可以工作就可以了,所以经常出现几千行的大类。系统应该是有许多短小的类而不是少量巨大的类组成。每个小类有单一的职责,只有一个修改的原因,所有这些小类在一起协同工作完成系统的功能。
高内聚:如果一个类中每个变量都被每个方法所使用,则该类有最大的内聚性。
保持内聚性得到许多短小的类。
上面说到每个类应该有单一职责,就是说类之间应该低耦合,但类的内部应该是高内聚的。如果一个类中的每个变量被每个类使用,则该类具有最大的内聚性。内聚性高说明变量和方法相互关联形成一个逻辑整体。
重构函数也会促使类职责的分离,看下面场景:
将一个有许多变量的大函数拆分成小函数,如果拆出来的代码使用了其中4个变量,那么就会将这4个变量作为参数传入到小函数中,如果使用的变量越多,就意味着小函数的参数越多,这时可以讲这4个变量升级成实体变量,小函数就不需要参数了,可以直接使用这些变量。这样就使内聚性变低,因为类中有很多的变量只为少数的函数服务,这时就可以将这些变量和函数拆分出来,单独成类。
开放闭合原则(OCP)
依赖倒置原则(DIP)
第十一章 系统
这一章主要讲的是怎样在较高的层级–系统层级来保持整洁。
将系统构造和使用分开:软件系统应该将启始过程和启始过程之后的运行时逻辑分离开,在启动过程中构建应用对象,也会存在相互缠结的依赖关系。
本章提到的一些技术概念,下面提供一些参考学习链接:
工厂模式
http://blog.fwhyy.com/2009/11/design-patterns-notes-3-abstract-factory-pattern/
依赖注入(DI)
控制反转(IOC)
http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html
扩容:不可能一开始就把系统做对,实现好当前客户的需求,然后重构,扩容来实现新的客户需求。
软件系统与物理系统可以类比。他们的架构都可以递增式增长,只要我们持续将关注面恰当的切分。
AOP
http://www.cnblogs.com/zhugenqiang/archive/2008/07/27/1252761.html
第十二章 迭进
Kent Beck关于简单设计的四条规则
1 运行所有测试
- 不可测试的系统是不可验证的,不可验证就不应该部署;
- 只要系统是可测试的,就会导向保持类的短小和单一的职责;
- 紧耦合的代码是难以编写测试的,所以编写测试越多,就会导致使用依赖注入、面向接口编程等来使代码解耦。
2 不可重复
3 表达程序员的意图
- 选好的变量名、函数名和类名;
- 要记住,下一个阅读你代码的很可能就是你自己;
- 添加适当的注释。
4 尽可能减少类和方法的数量
重构
- 上面的2-4点都可以通过重构的方法来达到;
- 重构的目的:提升内聚、降低耦合、切分关注面(AOP)、模块化系统性关注面、缩小函数和类的尺寸、选取好的名称等;
- 好的函数、好的类、好的系统是重构出来的,没有人能一开始就把事情做对;
- 重构应该要及时,发现了坏味道要及时重构,当然这个需要测试来做保障。