第一章-整洁代码
代码不会消失
糟糕的代码
我们都深受烂代码的伤害,但是我们为什么要制造烂代码呢?
我们都说过,以后再来处理代码中的丑陋。但是勒布兰法则:稍后等于永不(Later equals never)
混乱的代价
结果就是生产力不断下降
老代码无力维护,只能开发一套新的。花时间保持代码质量不知关乎效率,而且关乎生存。
需求的改变可能背离了最初的设计,这是烂代码产生的时机,也是重构的最好时机。
制造混乱无助于赶上期限,只会拖慢。保持代码整洁才是唯一的办法。
怎么写出整洁的代码?需要遵循大量的小技巧,刻苦习得“整洁感”。
什么是整洁的代码---优雅的,逻辑清楚的,只做好一件事。给人写的,可测试的,可修改的。没有重复代码。
读代码的时间:写代码的时间=10:1
军规:时时保持代码整洁。如果每次签入的代码比签出的要干净,那么代码就不会腐坏。
设计原则:PPP-原则、模式、实践。单一职责,依赖倒置,开闭原则等
第二章-有意义的命名
命名随处可见:变量、方法、类、包等等
名副其实
避免误导
做有意义的区分
避免a1,a2这样的命名
能读的出来
使用可搜索的名称
避免使用编码
例如这样前缀btnAbc
实现前加前缀I,也是不优雅的
避免思维映射
i,j,k一般用来命名循环变量,不宜它用
类名当用名词
方法明当是动词或动词短语
别开玩笑,严肃
对应每个概念,用一个词
Manager还是controller
拒绝用双关语
使用解决方案领域名词,次之使用问题领域的名词
添加语境
code---不如appCode
第三章--函数
好的函数该怎么写?
短小
越小越好,不多于20行为佳
嵌套不要多于一到两层,易于理解
只做一件事
如果函数只是做了其函数名下的同一抽象层的步骤,则函数还是只做了一件事
每个函数一个抽象层级
每个函数后面也跟着同一抽象层级的步骤
switch语句--天生就要干多件事
用多态来解决
使用描述性的名称
函数参数
最好是没有,越少越好,不要超过3个
参数多了对编写测试用例的难度加大
一元函数的普遍形式
问关于这个参数的某个问题
或者操作这个参数,比如做转换之类
标识参数丑陋不堪
向函数传如bool,意味着函数要干不止一件事
多元函数理解困难
参数多于3个就该封装对象了
分隔指令和询问
使用异常代替返回错误码
抽离try/catch代码块
把错误处理当成一件事
避免error.java
新增异常,所有相关的类都要重新编译
使用异常就不会发生这样的事
别重复
重复是一些邪恶的根源
打磨和重构
和写文章一样,写完函数后依据前面的原则进行修改
第四章--注释
别给糟糕的代码添加注释,重构吧。
- 不说废话
- 不误导
- 不得不写的时候才写
第五章--格式
代码尺寸,一个java文件200到500行
向报纸学习
源文件顶部给出最高层次的概念和算法
细节逐一展开
垂直方向分隔---空白行
垂直方向聚集
相似的定义集中
关系相近的概念放在一起
函数调用者放在被调用者的上方
水平方向保持短小
水平方向相关性弱的用空格分隔
缩进--符合规范
团队定义
第六章--对象和数据结构
数据抽象
隐藏实现,用户无需了解数据的实现就能操作数据
对象和数据结构
过程式代码便于不修改数据结构而添加新函数,面向对象代码便于不修改函数而增加新类。
德墨忒尔律
方法不调用任何函数返回的对象的方法。换言之,只和朋友谈话,不和陌生人谈话。
数据传送对象
只有公共变量,没有函数--如javabean
小结
灵活添加新数据类型时,使用对象;灵活添加行为时,使用数据类型和过程。
第七章--错误处理
使用异常而非错误码
先写try-catch-finally语句
try里面的内容像是事务,维护该范围的事务特征
使用不可控异常
按照调用者的需要来定义异常类
别返回null,避免传递null
小结
异常处理要独立于主逻辑之外
第八章--边界
使用第三方代码
如果使用类似Map这样的边界借口,就把它保留在近亲类中。
对第三方代码写测试
使用上不存在的代码
使用适配器
小结
在使用我们控制不了的代码时,要格外小心。确保未来的修改不会太大。
第九章--单元测试
TDD
三条定律:
编写不能通过的测试代码前,不写生产代码 只可编写刚好无法通过的单元测试,不能编译也不算通过 只可编写刚好通过当前失败测试的生产代码
保持测试整洁
应该和生产代码同样重要
测试带来一切
可扩展、可维护、可复用
整洁的测试
分为3步:构造数据、操作数据、检验操作
每个测试一个断言
FIRST原则
快速、独立、可重复、自足验证、及时
第十章--类
类的组织
要封装
类要保持短小
无法准确命名的时候,就表示权责太多了
单一职责原则
内聚
类中的每一个变量都被每一个方法使用,则具有最高的内聚性
保持函数和参数列表的短小策略,有时会导致实体变量增加;这是应该尝试将变量和方法分拆到多个类中。
为了修改而组织
第十一章--系统
如何在更高的抽象层级--系统层级上保持整洁
将系统的构造和使用分开
起始过程和运行时逻辑分离
分解main
将全部构造过程搬到main中,main函数创建所有的对象,再传递给应用
使用工厂
隔离构造细节
依赖注入
控制反转将第二责权拿出来,转移到另一个专注于此的对象中,从而遵循了单一职责原则
扩容
面向方面编程,Java相关机制
Java代理
待深入
纯Java AOP框架
待深入
AspactJ切面
测试驱动系统架构
使用POJO编写业务逻辑,在代码层面与架构关注面分离开,就有可能用测试来驱动架构。
最佳的系统架构由模块化的关注面领域组成,每个关注面均用JAVA对象构成。不同领域之间用不具有侵害性的方面工具整合起来。
优化决策
拥有模块化关注面的POJO系统提供的敏捷能力,允许我们基于最新的知识做出决策。
系统需要DSL
DSL领域特定语言允许所有抽象层级和应用程序中的所有领域,都使用POJO来表达。
第十二章--跌进
通过跌进设计达到整洁目的
kent back四原则
运行所有测试
设计的系统是否达到预期,需要通过验证。不能被测试的系统,不应部署
重构
修改代码就会导致新的问题,测试消除了这样的恐惧。
不可重复
重复是拥有良好设计的大敌。
模板方法模式是一种移除高层级重复有效的办法。
表达力
作者把代码写的越清晰,其他人花在读懂代码上的时间越少,从而减少缺陷,缩小维护成本。
尽可能少的类和方法
前面的几点更为重要
第十三章--并发编程
为什么要并发
是一种解耦策略,帮助我们把何时、做什么事情分开。
一些中肯的说法: 并发是很复杂的,即便很简单的系统 并发会在性能和编写代码增加一些开销 常常需要对设计策略进行根本性修改并发防御原则
单一职责原则--分离并发代码和非并发代码
限制数据的作用域
使用synchronized
使用数据副本
线程尽可能的独立、
了解java线程安全集
了解执行模型
- 限定资源
- 互斥
- 线程饥饿
- 死锁
- 活锁
线程模型:
- 生产者消费者模型
- 读者作者模型
- 宴席哲学家
避免使用一个同步对象的多个方法
测试线程代码
频繁运行,发现错误
自动化测试第十四章--逐步改进
通过重构一个冲虚讲解了何时需要改进、如何逐步改进
第十五章--JUnit框架
通过重构junit的一个类来展示了cleancode的方法,也证明了优秀的代码也能更好。