“相对于任何宏伟景愿,对细节的关注甚至是更为关键的专业性基础。首先,开发者经过小型实践得到可用于大型实践的技能和信用度。其次,宏伟建筑中最细小的部分,好比关不紧的门,有点儿没有铺平的地板,甚至是凌乱的桌面,都会将整个大局的魅力毁灭殆尽。这就是整洁代码之所系”----没有比书中的这段话更能说明这本书的意义了。java

《代码整洁之道》是第1期书山有路活动选出的读本。相对于记住那些如何写出整洁代码的那些法则,养成保持代码整洁、提升代码质量的习惯和思惟更为重要。全书大体分为三个部分,第一部分1-10章都是介绍如函数、类、命名、单元测试等保持整洁的建议。第二部分11-13章从系统设计的层面提倡用AOP、IOC等方式保持整洁,或者合适的时候使用并发编程。第三部分14-17章以及后面的附录,做者以JAVA源码(全书都是以JAVA代码示例)来实际讲解如何保持整洁。程序员
later equals never编程
咱们都曾经瞟一眼本身亲手形成的混乱,决定弃之不顾,走向新的一天。咱们都曾经看到本身的烂程序竟然能运行,而后断言能运行的烂程序总比什么都没有强,咱们都曾经说过有朝一日再回头清理。固然,在那些日子里。咱们都没有听过布朗法则:later equals never 稍后等于永不.设计模式
ps:看到这句话确实有点惭愧。印象最深的感受就是,咱们去看一两年前本身的代码。那是写的什么玩意,真的是本身都看不下去。要让我改,我情愿再实现一个。因此时刻保持好的习惯是多么重要。不要想着之后再解决。就像领导说,这个事情之后再考虑,而后就没有而后了。缓存
第一章 整洁代码 安全
怎样是整洁的代码?
Bjarne Stroustrup(C++发明者) 说:
“我喜欢优雅和高效的代码,代码逻辑应当直接了当,叫缺陷难以隐藏;尽可能减小依赖关系,使之便于维护;依据某种分层战略完善错误处理代码;性能调至最优,免得引诱别人作没有必要的优化,搞出一堆混乱来,整洁的代码之作好一件事。”
Ron Jeffries 对整洁代码的理解:
1.能经过全部的测试。
2.没有重复代码。
3.体现系统中的所有设计理念。
4.包含尽可能少的实体、好比类、方法、函数等。
“在以上诸项中,我最在乎的是代码重复。若是一段代码重复出现,就表示某种想法未在代码中获得良好的提现。我会尽力去找出到底那是什偶么,而后在尽力的更清晰的表达出来。”
PS:总结下就是整洁的代码1.职责明确,没有多余,2.减小依赖,便于维护。3.高效。
第二章 有意义的命名
1.名副其实。 提及来很简单。选个好名字须要花时间,但省下的时间比花掉的多。注意命名,一旦有好的命名,就换掉旧的。
int d;// 消失的时间,以日计。
int elapsedTimeInDays;
PS:Ctrl+R+R蛮好用的。实际中的状况要比我贴出来的复杂。咱们定义不一样的变量,可以看到名字就知道是什么意思,这是最基本的要求了。网络
2.避免误导。好比不是List类型,就不要用个accountList来命名,这样造成误导。数据结构
3.作有意的区分。
Public static void copyChars(char a1[],char a2[]){
for(int i=0;i<a1.length;i++)
{
a2[i]=a1[i];
} }
若是参数名称改成source和destination ,这个函数就会像样不少。废话都是冗余的,Variable一词 永远不该当出如今变量名中。Table一词永远不该当出如今表名中。NameString 会比 Name好吗,难道Name 会是一个浮点数不成?若有一个Customer的类,有又一个CustomerObject的类。是否是就凌乱了。并发
4.使用便于搜索的的名称编程语言
单个字母或者数字常量是很难在一大堆文章中找出来。好比字母e,它是英文中最经常使用的字母。长名胜于短名称,搜获得的名称胜于自编的名称。 窃觉得单字母的名称仅用于短方法中的本地变量。名称长短应与其做用域大小相对应。
5.类名应该是名词或短语,像Customer,Account,避免使用Manager,Processor,Data或者Info这样的类名。类名不该当是动词。方法名应该是动词或动词短语,如postPayment ,deletePage或Save,属性访问、修改和断言应该根据其值来命名,并加上get,set,is这些前缀。
6.别扮可爱,耍宝,好比谁知道HolyHandGrenada 函数是干什么的,没错这个名字挺伶俐,可是不过DeleteItems或许是更好的名字。
7.每一个概念对应一个词。而且一以贯之。
在一堆代码中有Controller,又有manager,driver。就会使人困惑。好比DeviceManager和Protal-Controller之间又什么本质区别?
第三章 函数
1.函数的第一规则是要短小,第二条规则是还要更短小。
2.函数应该作一件事。作好这件事。只作这一件事。
3.尽可能少的函数参数。有两个参数的函数要比一元函数的难懂。若是须要三个或者三个以上的参数应该封装成类了。
4.不要重复本身。
PS:若是一段相同的代码出现了两次,你是否是以为本身改作些什么了。
第四章 注释
注释的恰当用法是弥补咱们在用代码表达意图时遭遇的失败。做者认为注释是一种失败,咱们总没法找到不用注释就能表达自个人方法,因此总要有注释,这并不值得庆贺。写注释的常见动机之一是糟糕代码的存在。
带有少许注释的整洁而有表达力的代码,要比带有大量注释的零碎而复杂的代码像样的多。与其花时间编写解释你搞出的糟糕的代码注释,不如花时间清洁那堆糟糕的代码。
PS:这段话看起来可能有些过激。咱们确实能够经过好的编码习惯减小没必要要的注释。不过如今自动生成文档的技术都是从代码的注释中提取的。若是是这种状况,上司确定是要求你写完备的注释的。
好注释:
1. 法律信息。有时,公司代码规范要求编写与法律有关的注释。例如版权和著做申明。
2.提供信息的注释。
// returen an instance of the Responder being tested
protected abstract Responder responderInstance();
不过做者认为 将函数名 从新命名为 responderBeingTested 注释就是多余的。
3.对意图的解释。 有时注释不只提供了有关实现的有用信息,并且还提供了某个决定后面的意图。
4.阐释。 有时注释把某种晦涩难明的参数或返回值的意义翻译为某种可读形式。也会是有用的。特别是参数或者返回值是某个标准库的一部分,或者你不能修改代码,那帮助阐释其含义的代码就会有用,例如:
assertTrue(bb.compareTo(ba)==1);//bb>aa
assertTrue(a.compareTo(b)==-1);//a<b
直接看方法可能不明确,但有注释就明白多了。我看这2,3,4都是一个意思。就是说明是干吗的。
5.警示,告诉别人要注意这个方法之类的。
6.放大。有的代码可能看着有点多余,但编码者当时是有他本身的考虑,这个时候须要注释下这个代码的重要性。避免后面被优化掉。
第五章 格式
纵向格式:
1. 函数与函数之间留空行。
2.变量声明:变量声明应该尽量靠近其使用位置。由于函数很短,本地变量应该在函数的顶部出现。
3.实体变量 应该在内的顶部,至关于咱们的field 字段,会被使用的多。
4.相关函数,若是某个函数调用另一个,就应该把他们放在一块儿,并且调用者应该尽量放在被调用者的上面。这样这个程序就会天然有序。(以前我喜欢把private的方法 放到一块儿。固然这确实没有什么实际的意义)
5.“相关概念的代码放在一块儿。相关性越强,好比一个大功能逻辑靠在一块儿。” (更多的时候我喜欢用 region 来收起来。)
横向格式:
1.一行的长度,做者建议是上限是120个字符
PS 平时咱们都是按照本身的屏幕大小来决定,固然太长了,本身也不便阅读,又不是压缩的js文件
2.赋值语句两端留空。
3.不在函数名和左括号间加空格。由于函数与其参数密切相关。
4.缩进。源文件是一种继承结构,而不是一种大纲结构,继承结构中的每一层级都圈出一个范围, 也就是代码块,其中有声明语句和执行语句。要体现这种继承结构,就要对源代码进行缩进处理。但有时候咱们会把if语句,while循环,或小函数写成一行,但这样没有层级的概念,不便阅读,仍是缩进的好。
第六章 对象和数据结构
1.过程式代码(函数编程)便于在不改动既有数据结构的前提下添加新函数,面向对象代码便于在不改动既有函数的前提下添加新类。反过来说也说的通,过程式代码难以添加新的数据结构,由于必须修改全部函数,面向对象代码难以添加新函数,由于必须修改全部类。因此在设计的时候要分析好是之后是要添加新函数仍是要添加新的数据结构。
2.德墨忒尔律:模块不该该了解它所操做对象内部情形。好比C的方法f只能调用如下对象的方法。
- C
- 由f建立的对象
- 做为参数传递给f的对象
- C的实体变量持有的变量
var outpath=cxt.getOptions().getScart().getAbsolutePath();
这个代码就违反了上面的德墨忒尔律,调用了返回值的方法。这样就是暴露了内部结构。
第七章 异常处理
1.try代码就像是事务,catch代码块将程序维持在一种持续状态。在编写可能抛出异常的代码时,最好先写出try-catch-finally 语句。
2.根据须要定义异常类。对错误分类的方式有多种,能够依据来源,是组件仍是其余地方,或者依据类型,是设备错误仍是网络错误。不过在咱们定义异常类的时候,最重要的考虑是如何捕获它们。
3.别返回null值。程序中不断的看到检测null值的代码,一处漏掉检测就可能会失控。返回Null,做者认为这种代码很糟糕。建议抛出异常 或者返回特定对象(默认值)。更早的发现问题。同理,也应该避免传递Null值给其余的方法。
PS:在大多数的编程语言中,没有良好的方法能对付由调用者意外传入的null值。咱们发布产品应该有容错的机制,程序不能轻易的就崩掉,有异常应该及时记录下来或给出提示。
第八章 边界
有时候咱们在使用第三方程序包或者开源代码的时候,或者依靠公司其余团队的代码,咱们都得干净利落的的整合进本身的代码中。这一章就是介绍保持保持软件边界整洁的实践手段和技巧。
1.对第三方进行学习性测试,当第三方程序包发布了新的版本,咱们能够容许学习性测试,看看程序包的行为有没有发生改变。
2.使用尚不存在的代码,有时候咱们的第三方,尚未开发好API,但又不能影响到咱们的开发进度,因此咱们先能够定义好本身想要的接口。若是第三方ok了,咱们再对接起来。
3.经过接口管理第三方边界,可使用ADApter模式将个人接口转换为第三方提供的接口。这个是要注意,第三方的代码和本身的代码混合太多,这样不便管理。
第九章 单元测试
敏捷和TDD运动鼓舞了许多程序员编写自动化单元测试,单元测试是确保代码中的每一个犄角旮旯都如咱们所愿的工做。
TDD三定律
- 除非这能让失败的单元测试经过,不然不容许去编写任何的生产代码。
- 只容许编写恰好可以致使失败的单元测试。 (编译失败也属于一种失败)
- 只容许编写恰好可以致使一个失败的单元测试经过的产品代码。
PS:什么是生产代码,这里有点迷惑。
测试代码和生产代码同样重要,它可不是二等公民,它须要被思考、被设计和北照料。它该像生产代码同样保持整洁。单元测试让你的代码可扩展,可维护,可复用。缘由很简单,有了测试,你就不担忧对代码的修改,没有单元测试,每次修改可能带来缺陷,一个测试,一个断言。一个测试,对应一个概念。咱们不想要超长的测试函数。
测试还应遵照如下5条规则。
1.快速 测试应该能快速运行,太慢了你就不会频繁的运行,就不会尽早的发现问题。
2.独立。测试应该相互独立,某个测试不该该为下个测试设定条件。当测试相互依赖,一个没经过致使一连串的测试失败,使问题诊断变的困难。
3.可重复。测试应该能够在任何环境中重复经过。
4.自足验证 测试应该有布尔值输出,不管经过或失败,不该该是查看日志文件去确认
5.及时。单元测试应该刚好在使其经过的生产代码以前编写。
第十章 类
1.类应该短小
2.单一权责原则(SRP):类或模块应有且只有一条加以修改的理由。系统应该有许多短小的类而不是巨大的类组成。
PS:每一个达到必定规模的系统都会包括大量逻辑和复杂性。管理这种复杂性的首要目标就是加以组织,以便开发者在哪儿能找到东西,反之,
拥有巨大、多目的的类的系统,老是让咱们在目前并不须要了解的一大堆东西中艰难的跋涉。
3.内聚:若是一个类中的每一个变量都被每一个方法所使用,则该类具备最大的内聚性。内聚性高,意味着类中的方法和变量相互依赖,相互结合成一个逻辑总体。
4.为了修改而组织。开放闭合原则(OCP):类应当对扩展开放,对修改封闭。咱们能够借助接口和抽象类来隔离这些细节带来的影响。
第十一章:系统
将系统的构造和使用分开:构造和使用是不同的过程。
PS:修建一栋大楼的时候,起重机和升降机在外面,工人们穿着安全服在忙碌。当大楼建设完成,建筑物变得整洁,覆盖着玻璃幕墙和漂亮的漆色。在其中工做的人,看完彻底不一样的景象。软件也是如此,将关注的方面分离。
1.工厂,有时候应用程序须要肯定什么时候建立对象,咱们可使用抽象工厂模式。将构造的细节隔离于应用程序以外。
2.依赖注入(DI/IOC)。在依赖管理情景中,对象不该该负责实例化对自身的依赖,反之,它应该将这份权责移交给其余有权利的机制,从而实现控制的反转。
PS 如今的依赖注入组件比较多了,Autofac,Ninject等。
3.扩容:“一开始就作对的系统”纯属神话,反之,咱们应该只实现今天的用户的需求。而后重构,明天再扩容系统,实现新用户的需求。这就是迭代和增量敏捷的精髓所在。 就像城市不断的再拆掉,再建设。
4.面向切面编程。AOP中,被称为方面(aspect)的模块构造指明了系统中哪些点的行为会以某种一致的方式被修改,从而支持某种特定的场景。这种说明是用某种简洁的声明(Attribute)或编程机制来实现的。
PS:MVC的Filter是个很好的AOP,能够从权限验证,方法进入前,方法进入后,返回结果前,返回结果后等这几个横切面进行编程。更好的组织代码。第十,十一章讲的设计只是一少部分。更多的可能要去参考专门讲设计模式之类的书。
第十二章 迭进
1.简单设计规则 1:运行全部测试。
紧耦合的代码难以编写测试。一样编写测试越多,就会越遵循DIP之类的原则,使用依赖注入,接口和抽象等工具尽量减小耦合。如此一来设计就会有长足进步。遵循有关编写测试并持续运行测试的、明确的规则,系统就会更贴近OO低耦合度、高内聚的目标。
2.简单设计规则2 重构:
在重构过程当中,能够应用有关优秀软件设计的一切知识,提高内聚性,下降耦合度。换句话说:消除重复,保证表达力,尽量的减小类和方法的数量。
3.不可重复。重复是良好设计系统的大敌。它表明着额外的工做、额外的风险和额外没必要要的复杂度。重复有多种表现。雷同的代码行是一种。另外的好比:
int size();
bool isEmpty();
这两个方法能够分别实现,但能够在isEmpty中使用size消除重复。
bool isEmpty(){
return size()==0;
}
不可是从代码行的角度,也要从功能上消除重复。
第十三章: 并发编程
并发是一种解耦策略,它帮助咱们把作什么(目的)和什么时候(时机)作分解开。在单线程应用中,目的与时机紧密耦合,不少时候只要查看堆栈追踪便可判定应用程序的状态。而解耦目的与时机能明显地改进应用程序的吞吐量和结构。从结构的角度看,应用程序看起来更像是许多台协同工做的计算机,而不是一个大循环。单线程程序许多时间花在等待Web套接字I/O结束上面。
- 并发会在性能和编写额外代码上增长一些开销。
- 正确的并发是复杂的,即便对于简单的问题也是如此。
- 并发缺陷并不是总能重现,因此常被看作偶发事件而忽略,而未被当作真的缺陷看待。
- 并发经常须要对设计策略的根本性修改。
一些基础定义:
在并发编程中用到的几种执行模型。
1)生产者-消费者模型
一个或多个生产者线程建立某些工做,并置于缓存或者队列中。一个或者多个消费者线程从队列中获取并完成这些工做。生产者和消费者之间的队列是一种限定资源。
2)读者-做者模型。
当存在一个主要为读者线程提供信息源,但只是偶尔被做者线程更新的共享资源,吞吐量就会是个问题。增长吞吐量,会致使线程饥饿和过期信息的积累。协调读者线程不去读取正在更新的信息,而做者线程倾向于长期锁定读者线程。
3)宴席哲学家。
许多企业级应用中会存在进程竞争资源的情形,若是没有用心设计,这种竞争会遭遇死锁,活锁,吞吐量和效率低等问题。
PS:这里对并发的讲解还不是那么的清晰,要掌握怎么正确使用并发,本身仍是须要去专门看看这方面的书。
小结:书十三章以后的部分是一些java源码的优化过程的讲解,我不太懂java,这里先略过。本书最有价值的地方在于让咱们程序员要有些整洁代码的习惯。从细微的变量命令,到函数、类的设计、以及整个系统的构造。不能忽略每一道工序。坏的代码就像沼泽,会让人越陷越深,很难改动,因此咱们从一开始就要写整洁的代码。而至于设计模式或并发编程,从其余的书籍
学习
更全面。这本书知足不了咱们的需求。
PS:书山有路活动是读书群的朋友共同选出来一块儿读的一本书。《代码整洁之道》是第一期。我是读书人,这本书一共读了七天。天天大概一个多小时。可是今天整理笔记,基本上全书又过了一遍。笔记内容也是依据我本身的判断。若是你想得到全面的了解,仍是要请看原书。咱们第二期正在读的书籍是《失控》,欢迎有兴趣的朋友加入。qq群452450927