@TOC
在线浏览:书栈网:https://www.bookstack.cn/read…
每个章节都会做一个本人的总结,并为这个章节打一个重要性的参考分数,满分五星(仅集体的角度)。
如果想尽快的理解一些代码的标准,最难看一下阿里代码标准,idea 也能够装置阿里代码标准插件。
阿里开发手册是实际,这本书自身更多的是作者理念疏导。理念的疏导必然少不了佐证、和一些看似冗余的语句,但这都是咱们站在现在开发环境上的后果论,因为所有技术性文章都是具备很强的时效性。
第 1 章 Clean Code 整洁代码(3 星)
第一章次要介绍这本书的背景和用意,以及总结下整洁代码的理念
有的章节几节能够间接越过,然而看完的话既知所以然,又知其然
?为什么要整洁的代码
反证:蹩脚代码的害处
团队中各司其职,代码是代码人应有的责任,要被动保护,去压服那些妨碍咱们优化的。。。
?什么叫做整洁代码
每个人对于整洁的定义都不同,这里只是作者代表的一些理念,要学会自我思考
- 用意明确:只做一件事,进步表达力
- 扩展性:提前构建小规模、简略形象
- 简洁:缩小反复代码,包含尽量少的实体,比方类、办法、函数等
- 正确性:能通过所有测试
- 体现零碎中的全副设计理念
- 读与写破费工夫的比例超过 10:1,代码浏览重要性,要对本人的读者负责
- 整洁代码须要从点滴做起
胜利的案例并不能让你成为成功者,只能分享给他人胜利的过程,技巧
第 2 章 Meaningful Names 有意义的命名(3 星)
语义明确,语境明确,不冗余
- 语义明确:最好通过变量名解说变量的意义,而不是正文。例如:魔法值,就是不能明确意义的常量
- 防止误导:例如:缩写不明确;专有名词同名;命名类型不精确;类似命名放一起辨别,明确正文;类似数字字母不明确
- 有意义的辨别,废话都是冗余。比方:Table 一词永远不该当呈现在表名中
- 应用能够读的进去的名称
- 应用能够搜寻的名字:单字母名称和数字常量仅用在短办法中的本地变量,最好不要用
- 防止思维映射:不要你感觉,他人也会这样感觉
- 类名和对象名应该是名词或名词短语,不该当是动词
- 办法名该当是动词或动词短语
重载结构器时,应用形容了参数的动态工厂办法名。例如,
Complex fulcrumPoint = Complex.FromRealNumber(23.0);
通常好于
Complex fulcrumPoint = new Complex(23.0);
能够思考将相应的结构器设置为 private,强制应用这种命名伎俩。
- 别用双关语
- 应用程序员相熟的术语,或者所涉问题畛域命名
- 增加有意义的语境:对字段进行补充阐明
第 3 章 Functions 函数(3 星)
本章所讲述的是无关编写良好函数的机制
- 函数的第一规定是要短小
- 函数应该只做好这一件事
- 每个函数一个形象层级
让代码读起来像是一系列自顶向下的 TO 起头段落是放弃形象层级协调一致的无效技巧
- switch
利用多态来实现,确保每个 switch 都埋藏在较低的形象层级,而且永远不反复
例子:所有的员工都有一样的流程,是否发薪日、计算薪水、发薪水,然而不同类型的员工具体流程动作不一样
public Money calculatePay(Employee e)
throws InvalidEmployeeType {switch (e.type) {
case COMMISSIONED:
return calculateCommissionedPay(e);
case HOURLY:
return calculateHourlyPay(e);
case SALARIED:
return calculateSalariedPay(e);
default:
throw new InvalidEmployeeType(e.type);
}
}
多态实现:更改之后再减少职员类型,每种职工只须要做本人的事件,不须要所有的类型当办法都更改,只需更改实现工厂实现类
public abstract class Employee {public abstract boolean isPayday();
public abstract Money calculatePay();
public abstract void deliverPay(Money pay);
}
-----------------
public interface EmployeeFactory {public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
-----------------
public class EmployeeFactoryImpl implements
EmployeeFactory {public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {switch (r.type) {
case COMMISSIONED:
return new CommissionedEmployee(r);
case HOURLY:
return new HourlyEmployee(r);
case SALARIED:
return new SalariedEmploye(r);
default:
throw new InvalidEmployeeType(r.type);
}
}
}
- 应用描述性的名称
别胆怯长名称、别胆怯花工夫取名字、命名形式要保持一致
- 函数参数: 最现实的参数数量是零
- 无副作用函数:不要把相关性不强的逻辑放进来,强调复用性
- 分隔指令与询问:防止凌乱
- 应用异样代替返回错误码
if (deletePage(page) == E_OK) {if (registry.deleteReference(page.name) == E_OK) {if (configKeys.deleteKey(page.name.makeKey()) == E_OK) {logger.log("page deleted"); } else {logger.log("configKey not deleted"); } } else {logger.log("deleteReference from registry failed"); }} else {logger.log("delete failed"); return E_ERROR;}
On the other hand, if you use exceptions instead of returned error codes, then the error processing code can be separated from the happy path code and can be simplified:
另一方面,如果应用异样代替返回错误码,错误处理代码就能从主门路代码中分离出来,失去简化:
复制代码 try {deletePage(page); registry.deleteReference(page.name); configKeys.deleteKey(page.name.makeKey());} catch (Exception e) {logger.log(e.getMessage());}
- 反复可能是软件中所有邪恶的本源
- 好的代码须要缓缓打磨,精简,优化(这正是我喜爱的过程,乐此不疲)
第 4 章 Comments 正文(2 星)
作者毕竟站在英语母语的根底上,还是要思考下咱们本人的环境
- 正文不能丑化蹩脚的代码,正文不能成为蹩脚代码的发言人,代码才是外围
- 别误导,别废话,适时整顿 TODO、正文的代码块
第 5 章 Formatting 格局(1 星)
简直不必看
- 垂直、横向格局:代码缩进
第 6 章 Objects and Data Structures 对象和数据结构(4 星)
对象曝露行为,暗藏数据。便于增加新对象类型而无需批改既有行为,同时也难以在既有对象中增加新行为。
数据结构曝露数据,没有显著的行为。便于向既有数据结构增加新行为,同时也难以向既有函数增加新数据结构。
- 数据抽象:数据封装,暗藏具体行为
- 数据、对象的反对称性
过程式代码(应用数据结构的代码)便于在不改变既有数据结构的前提下增加新函数。面向对象代码便于在不改变既有函数的前提下增加新类。
- 得墨忒耳律
办法不应调用由任何函数返回的对象的办法
下列代码违反了得墨忒耳律(除了违反其余规定之外),因为它调用了 getOptions()返回值的 getScratchDir()函数,又调用了 getScratchDir()返回值的 getAbsolutePath()办法。
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
第 7 章 Error Handling 错误处理(4 星)
在本章中,要列出编写既整洁又强固的代码——优雅地解决错误代码的一些技巧和思路
整洁代码是可读的,但也要强固。可读与强固并不抵触。如果将错误处理隔离对待,独立于次要逻辑之外,就能写出强固而整洁的代码
- 应用异样而非返回码,用对立异样解决解决异样
- 在编写可能抛出异样的代码时,先写 Try-Catch-Finally 语句
- 应用不可控异样,可控异样的代价就是违反凋谢 / 闭合准则
- 给出异样产生的环境阐明
- 依调用者须要定义异样类
咱们在应用程序中定义异样类时,最重要的思考应该是它们如何被捕捉,而后依据捕捉法则去优化异样捕捉
- 别返回 null 值
- 别传递 null 值
第 9 章 Unit Tests 单元测试(3 星)
- 放弃测试整洁,测试代码和生产代码一样重要
- 整洁的测试,最重要的因素是可读性
- 每个测试一个断言
- 测试应该有以下规定:疾速、独立、可反复、自足验证、及时
第 10 章 Classes 类(5 星)
代码组织的更高层面——Classes
- 将零碎的结构与应用离开
- 类的组织
遵循规范的 Java 约定,类应该从一组变量列表开始。如果有公共动态常量,应该先呈现。而后是公有动态变量,以及公有实体变量。很少会有公共变量。公共函数应跟在变量列表之后。封装
- 类应该短小
对于函数,咱们通过计算代码行数掂量大小。对于类,咱们采纳不同的掂量办法,计算权责(responsibility)。类的名称该当形容其权责,从命名开始标准。
繁多权责准则(SRP)认为,类或模块应有且只有一条加以批改的理由。零碎应该由许多短小的类而不是大量微小的类组成。每个小类封装一个权责,只有一个批改的起因,并与多数其余类一起协同达成冀望的零碎行为。
内聚:类应该只有大量实体变量。类中的每个办法都应该操作一个或多个这种变量。通常而言,办法操作的变量越多,就越黏聚到类上。
扩展性:需要会扭转,所以代码也会扭转。具体类蕴含实现细节(代码),而抽象类则只出现概念。依赖于具体细节的客户类,当细节扭转时,就会有危险。咱们能够借助接口和抽象类来隔离这些细节带来的影响。依赖倒置准则(Dependency Inversion Principle,DIP),DIP 认为类该当依赖于形象而不是依赖于具体细节。
繁多权责和内聚都是水平值,保障的他们均衡 ,逻辑内聚,权责解耦,这并不简略,SRP 也充分考虑到了代码扩展性。
第 11 章 Systems 零碎(5 星)
本章将探讨如何在较高的形象层级——零碎层级——上放弃整洁
无论是设计零碎或独自的模块,别忘了应用大略可工作的最简略计划。
- 将零碎的结构与应用离开(编译和运行,java 的环境中 Spring 通过依赖注入(Dependency Injection,DI),管制反转(Inversion of Control,IoC)曾经帮咱们把这件事做了)。延后初始化的益处:这种伎俩在 DI 中也有其作用。首先,少数 DI 容器在须要对象之前并不结构对象。其次,许多这类容器提供调用工厂或结构代理的机制,而这种机制可为提早赋值或相似的优化解决所用。
- AOP:在 AOP 中,被称为方面(aspect)的模块结构指明了零碎中哪些点的行为会以某种统一的形式被批改,从而反对某种特定的场景。这种阐明是用某种简洁的申明或编程机制来实现的。
- 代理:应用代理,代码量和复杂度是代理的两大弱点,创立整洁代码变得很难!另外,代理也没有提供在零碎范畴内指定执行点的机制,而那正是真正的 AOP 解决方案所必须的
- 污浊的 Java AOP 框架:Bean 工厂内,每个 bean 就像是嵌套“俄罗斯套娃”中的一个,每个由数据存取器对象(DAO)代理(包装)的 Bank 都有个域对象,而 bean 自身又是由 JDBC 驱动程序数据源代理。通过 XML/ 注解的形式缩小对代码的入侵,只留下纯 POJO。
- AspectJ ASPECTS AspectJ 的方面:AspectJ 却提供了一套用以切分关注面的丰盛而强有力的工具。
- 测试驱动零碎架构:大设计(Big Design Up Front,BDUF)——零碎架构。最佳的零碎架构由模块化的关注面畛域组成,每个关注面均用纯 Java(或其余语言)对象实现。不同的畛域之间用最不具备侵害性的方面或类方面工具整合起来。这种架构能测试驱动,就像代码一样。
- 优化决策:模块化和关注面切分成就了分散化治理和决策。领有模块化关注面的 POJO 零碎提供的麻利能力,容许咱们基于最新的常识做出优化的、机会 刚好的决策。决策的复杂性也升高了。
- 抉择适合的架构——规范
- 零碎须要畛域特定语言:畛域特定语言(Domain-Specific Language,DSL)。DSL 是一种独自的小型脚本语言或以规范语言写就的 API,领域专家能够用它编写读起来像是组织谨严的散文个别的代码。畛域特定语言容许所有形象层级和应用程序中的所有畛域,从高级策略到底层细节,应用 POJO 来表白。
第 12 章 Emergence 迭进
本章中写到的实际来自于本书作者数十年教训的简练总结。遵循简略设计的实际伎俩,开发者不用经年学习就能把握好的准则和模式。
晋升内聚性,升高耦合度,切分关注面,模块化系统性关注面,放大函数和类的尺寸,选用更好的名称,如此等等。这也是利用简略设计后三条规定的中央:打消反复,保障表达力,尽可能减少类和办法的数量。
通过迭进设计达到整洁目标,Kent Beck 对于简略设计的四条规定,据 Kent 所述,只有遵循以下规定,设计就能变得“简略”,以下规定按其重要水平降序排列:
- 运行所有测试;
- 不可反复;
- 表白了程序员的用意;
- 尽可能减少类和办法的数量;
第 13 章 Concurrency 并发编程(5 星)
“对象是过程的形象。线程是调度的形象。”——James O
这个章节次要讲述了并发编程的起源、劣势和劣势,以及如何防止、解决并发谬误的办法和方向
? 为什么要并发
- 并发是一种解耦策略。
- 解耦目标与机会能显著地改良应用程序的吞吐量和构造。
- 并发会在性能和编写额定代码上减少一些开销;
- 正确的并发是简单的,即使对于简略的问题也是如此;
- 并发缺点并非总能重现,所以常被看做偶发事件而疏忽,未被当做真的缺点对待;
- 并发经常须要对设计策略的根本性批改。
并发进攻准则
- 繁多权责准则
繁多权责准则(SRP)认为,办法 / 类 / 组件该当只有一个批改的理由。并发设计本身足够简单到成为批改的理由,所以也该从其余代码中分离出来。可怜的是,并发实现细节经常间接嵌入到其余生产代码中。
须要思考的问题:
并发相干代码有本人的开发、批改和调优生命周期;
开发相干代码有本人要凑合的挑战,和非并发相干代码不同,而且往往更为艰难;
即使没有周边应用程序减少的累赘,写得不好的并发代码可能的出错形式数量也曾经足具挑战性。
倡议:拆散并发相干代码与其余代码。
- 限度数据作用域
两个线程批改共享对象的同一字段时,可能相互烦扰,导致未预期的行为。解决方案之一是采纳 synchronized 关键字在代码中爱护一块应用共享对象的临界区(critical section)。限度临界区的数量很重要。更新共享数据的中央越多,就越可能:
谨记数据封装;严格限度对可能被共享的数据的拜访。
防止共享数据的好办法之一就是一开始就防止共享数据。
线程应尽可能地独立,让每个线程在本人的世界中存在,不与其余线程共享数据。
理解 Java 库
学习类库,理解根本算法。了解类库提供的与根底算法相似的解决问题的个性。
理解执行模型
学习这些根底算法,了解其解决方案。
- Producer-Consumer 生产者 - 消费者模型
- Readers-Writers 读者 - 作者模型
- Dining Philosophers 哲学家用餐模式
警觉同步办法之间的依赖
- 防止应用一个共享对象的多个办法
- 有时必须应用一个共享对象的多个办法,有 3 种应答伎俩:
- 基于客户端的锁定——客户端代码在调用第一个办法前锁定服务端,确保锁的范畴笼罩了调用最初一个办法的代码;
- 基于服务端的锁定——在服务端内创立锁定服务端的办法,调用所有办法,而后解锁。让客户端代码调用新办法;
- 适配服务端——创立执行锁定的中间层。这是一种基于服务端的锁定的例子,但不批改原始服务端代码。
尽可能减小同步区域
尽早思考敞开问题,尽早令其工作失常。
测试线程代码
编写有后劲曝露问题的测试,在不同的编程配置、系统配置和负载条件下频繁运行。如果测试失败,跟踪谬误。别因为起初测试通过了起初的运行就疏忽失败。
有一大堆问题要思考。上面是一些简练的倡议:
- 将伪失败看作可能的线程问题,不要将零碎谬误归咎于偶发事件
- 先使非线程代码可工作, 不要同时追踪非线程缺点和线程缺点。确保代码在线程之外可工作。
- 编写可插拔的线程代码,这样就能在不同的配置环境下运行。
- 编写可调整的线程代码,要取得良好的线程均衡,经常须要试错。一开始,在不同的配置环境下监测零碎性能。要容许线程数量可调整。在零碎运行时容许线程产生变动。容许线程根据吞吐量和零碎使用率自我调整。
- 运行多于处理器数量的线程,零碎在切换工作时会产生一些事。为了促使工作替换的产生,运行多于处理器或处理器外围数量的线程。工作替换越频繁,越有可能找到错过临界区或导致死锁的代码。
- 在不同平台上运行
- 安装试错代码,并强制谬误产生:有两种安装代码的办法:硬编码、自动化
第 15 章 JUnit Internals JUnit 底细(2 星)
本章介绍了 JUnit 的一些简略的模块
第 16 章 重构 SerialDate(4 星)
本章详解对 org.jfree.date 库中的 SerialDate 日期类进行重构,简化的过程。减少了测试覆盖率,修复了一些谬误,廓清并放大了代码。
第 17 章 滋味与启发(3 星)
本章又列举了作者之前列出过的,一些不好的习惯,并把这些比作难闻的气息
洁净的代码不是通过遵循一组规定来编写的。
附录 A 并发编程 II(4 星)
并发编程的一些裁减信息,多了很多的示例解说
在本章中,咱们谈到并发更新,还有清理及防止同步的规程。咱们谈到线程如何晋升与 I/O 无关的零碎的吞吐量,展现了取得这种晋升的整洁技术。咱们谈到死锁及洁净地防止死锁的规程。最初,咱们谈到通过安装代码裸露并发问题的策略。
- 死锁
死锁的产生须要 4 个条件:
互斥:无奈在同一时间为多个线程所用;数量上有限度
这种资源的常见例子是数据库连贯、关上后用于写入的文件、记录锁或是信号量。
上锁及期待:当某个线程获取一个资源,在获取到其余全副所需资源并实现其工作之前,不会开释这个资源。
无领先机制:线程无奈从其余线程处篡夺资源。一个线程持有资源时,其余线程取得这个资源的惟一伎俩就是期待该线程开释资源。
循环期待:这也被称为“死命拥抱”。设想两个线程,T1 和 T2,还有两个资源,R1 和 R2。T1 领有 R1,T2 领有 R2。T1 须要 R2,T2 须要 R1。
这 4 种条件都是死锁所必须的。只有其中一个不满足,死锁就不会产生。
防止死锁的一种策略是躲避互斥条件。你能够:
- 应用容许同时应用的资源;
- 减少资源数量,使其等于或大于竞争线程的数量;
- 在获取资源之前,查看是否可用。
- 不上锁及期待
- 满足领先机制
- 不做循环期待
将解决方案中与线程相干的局部分隔进去,再加以调整和试验,是取得判断最佳策略所需的洞见的邪道。
总结
洁净有经验值,也有固定分,不是通过遵循一组规定来编写的,须要的是迭进,不须要钻牛角尖。
读英文原文的时候忽然想到:英语大多是后果论,喜爱陈说事实,就如同罪犯的对白