在线阅读:书栈网:https://www.bookstack.cn/read/Clean-Code-zh/spilt.8.docs-ch1.md
每个章节都会做一个自己的总结,并为这个章节打一个主要性的参考分数,满分五星(仅个人的角度)。
如果想尽快的理解一些代码的规范,最好看一下阿里代码规范,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 种条件都是去世锁所必需的。只要个中一个不知足,去世锁就不会发生。
避免去世锁的一种策略是规避互斥条件。你可以:
利用许可同时利用的资源;增加资源数量,使其即是或大于竞争线程的数量;在获取资源之前,检讨是否可用。不上锁及等待知足抢先机制不做循环等待将办理方案中与线程干系的部分分隔出来,再加以调度和试验,是得到判断最佳策略所需的洞见的正道。
总结干净有履历值,也有固定分,不是通过遵照一组规则来编写的,须要的是迭进,不须要钻牛角尖。
读英文原文的时候溘然想到:英语大多是结果论,喜好陈述事实,就彷佛罪犯的对白