后端好书阅读与推荐(续)

续前文 后端好书阅读与推荐 - Mageek`s Wonderland ,几十天过去了,又看了两本好书(还有之前看过的书),这里依然把它们总结概括一下,加入一些本身的见解、有用的连接和可能的延伸阅读,并推荐给须要的同窗。php

深刻理解Java虚拟机

深刻理解Java虚拟机 (豆瓣) https://book.douban.com/subje...html

Java怎么用,是一个问题;怎么用好是一个大问题;这么用是为何,是一个更大的问题。搞懂这三个问题应该是每个搞Java的人都要追求的目标,读完本书,就能把这个更大的问题搞懂了。java

本书亮点:node

  • 模块化是解决应用系统与技术平台愈来愈复杂,愈来愈庞大的问题的一个重要途径,也是创建各类功能的标准件的前提。ios

  • Java运行时数据区几个主要部分:程序计数器(可看做当前线程所执行的字节码的行号指示器)、虚拟机栈(每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程,而栈帧存储局部变量表、 操做数栈、 动态连接、 方法出口等信息)、本地方法栈(Native方法对应的栈)、(全部线程共享的一块内存区域,存放对象实例)、方法区(各个线程共享的内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据)、常量池(方法区的一部分,存放编译期生成的各类字面量和符号引用)。nginx

  • 对象访问方式取决于虚拟机实现而定的,目前主流的访问方式有使用句柄和直接指针两种:若是使用句柄访问的话,那么Java堆中将会划分出一块内存来做为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息;若是使用直接指针访问,reference中存储的直接就是对象地址。git

  • Java垃圾回收采用分代回收机制,新生代和老生代采用不一样的算法(node.js也是),而无论什么机制,判断一个对象是否存活都是基本的步骤,方法有:引用计数法,给对象添加一个引用计数器,每当一个地方引用它时,计数器就加1,引用失效时,计数器就减1,任什么时候刻计数器为0的对象就是不可能再被使用的,这个方法实现简单,可是不能解决循环引用问题,因此主流JVM不使用,可是这个算法也适用于许多地方如Python,微软的COM;可达性分析,按照对象之间的引用关系维护一个引用链,若是一个对象不可达GC Roots,那么就是可回收的,应用于主流JVM中。程序员

  • finalize是一种迎合C++程序员的妥协,运行代价高昂,不肯定性大,没法保证各个对象的调用顺序。有些教材中描述它适合作“关闭外部资源”之类的工做,这彻底是对这个方法用途的一种自我安慰。finalize能作的全部工做,使用try-finally或者其余方式均可以作得更好、更及时,因此建议你们彻底能够忘掉Java语言中有这个方法的存在。web

  • 几乎各类语言或多或少都提供过一些语法糖来方便程序员的代码开发,这些语法糖虽然不会提供实质性的功能改进,可是它们或能提升效率,或能提高语法的严谨性,或能减小编码出错的机会。不过也有一种观点认为语法糖并不必定都是有益的,大量添加和使用“含糖”的语法,容易让程序员产生依赖,没法看清语法糖的糖衣背后代码的真实面目。因此咱们既要会使用语法糖,同时也要搞懂背后的原理,这样才能进阶呀。好比泛型技术:泛型只在程序源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型。redis

  • Java程序最初是经过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定“热点代码”(Hot Spot Code)。 为了提升热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各类层次的优化,完成这个任务的编译器称为即时编译器(Just In Time Compiler,简称JIT编译器)

  • 基于高速缓存(Cache)的存储交互很好地解决了处理器与内存的速度矛盾,可是也为计算机系统带来更高的复杂度,由于它引入了一个新的问题:缓存一致性;除了增长高速缓存以外,为了使得处理器内部的运算单元能尽可能被充分利用,处理器可能会对输入代码进行乱序执行(Out-Of-Order Execution)优化,相似的JVM也有指令重排(Instruction Reorder)。这两点是提升程序运行的主要方法,然而也是多线程程序难以正确编写的主要缘由。

  • 先行发生(happens-before)是Java内存模型中定义的两项操做之间的偏序关系,若是说操做A先行发生于操做B,其实就是说在发生操做B以前,操做A产生的影响能被操做B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。时间前后顺序与先行发生原则之间基本没有太大的关系,因此咱们衡量并发安全问题的时候不要受到时间顺序的干扰,一切必须以先行发生原则为准。

这本书是基于jdk1.7的,若是要追踪最新的Java和JVM规范,能够看这里
另外,上面提到的第一个问题能够参阅Java核心技术,第二个问题能够参阅Java编程思想Effective Java,第三个问题还能够参阅HotSpot实战。这几本书我都浏览过,部分有细读,都是至关经典的。

高性能MySQL

高性能MySQL (豆瓣) https://book.douban.com/subje...

这本书可谓是MySQL领域的权威之做,从架构到测试,从性能分析到查询优化,从软件配置优化到服务器硬件优化,从单实例到主从复制、负载均衡,从底层数据库优化到应用层优化......本书真可谓是面面俱到,同时又颇有深度,绝非浅尝辄止。

本书亮点:

  • 所谓的锁策略,就是在锁的开销和数据的安全性之间寻求平衡,这种平衡天然也影响到性能。这句话适用于世间的一切工具,安全性和可用性老是矛盾的,咱们在使用工具或者开发工具的时候,都要寻求一个最佳平衡点

  • 除非须要使用InnoDB不具有的的特性,而且没有其余办法能够替代,则都应该优先使用InnoDB引擎,也不要多引擎混用,例如全文索引能够使用InnoDB+Sphinx,而不要使用MyISAM引擎,由于InnoDB其余方面的优势能够彻底碾压MyISAM,好比崩溃恢复快,支持事务,支持行级锁,支持真正的热备份等等。

  • 基准测试能够验证对于系统的假设,检查异常行为,找出扩展性瓶颈等等。须要注意的是不要使用真实数据的子集,做物的数据分布,忽略预热等等,这些错误的操做会使得测试结果无用或者不精确。并且要创建参数与结果文档化的规范,这样才利于结果分析与优化。

  • 不少人在优化时都将精力放在修改某些东西上,却不多去测量;正确的作法是要尽可能测量响应花的时间在哪,正确的测量通常都能将性能问题的点暴露出来,咱们就能更好的对症下药,而不是盲目优化(花1000块优化一个只值500块的业务,或者已经处于顶点的业务不就是亏了吗)。因此说,决策要基于数据而不是感受。

  • 良好的逻辑设计和物理设计是高性能的基石,某些反范式的设计可能加快某些查询,好比计数表和汇总表是一种很好的查询优化方式,能提升统计类的查询速度,可是维护起来就比较麻烦,可能下降数据插入速度。这些都须要本身根据业务来进行权衡(好比读写比),有阴就有阳嘛。

  • 选择能正确存储数据的最小类型:既省空间又省计算时间,简单就好:好比使用MySQL内建时间戳而不是本身使用字符串,尽可能避免null:由于null使得索引、统计、值比较都更加复杂还可能会占用更多空间。

  • InnoDB有一个“自适应哈希索引”的功能,当引擎注意到某些索引值被频繁使用时就会在内存中基于B+Tree索引之上再建立一个hash索引,这样就让B+Tree也具备hash索引的优势好比快速查找。

  • 小表一般全表扫描更高效,中大型表才适合用索引,使用索引过程当中要注意,索引列必须单独的出如今比较符号的右侧而不是表达式的一部分(这会使索引失效),使用前缀索引来节省空间提升检索效率,多列索引要注意顺序否则容易失效,聚簇索引能够提升访问速度。

  • 慢查询优化:只向数据库请求须要的列(好比不要随意select * )、避免没必要要的行扫描、必要的时候分解查询(拆分大的查询,分解关联查询)。

  • 默认配置文件是通过大量测试,因此属于较优解,通常符合普通用户,要修改也主要是根据业务而不是服务器配置;任何打算长期使用的配置都应该写到全局配置文件而不是在命令行指定,由于若是偶然启动忘了(事实是常常会忘,好记性不如烂笔头是个真理)设置就会有风险。

  • MySQL复制功能不只有利于构建高性能应用,同时也是高可用性(负载均衡、故障切换)、可扩展性(升级)、灾难恢复、备份以及数据仓库等工做的基础。

  • 数据若是很是庞大,好比几亿行了,单台机器已经撑不住了,一般要采起分片技术,分片最大的问题就是查询与获取数据,咱们的目标是对最重要且频繁查询的数据减小分片(热点数据一般就那么多)。因此分片关键问题就在于选择一个好的分区键,一般是一个数据库中很是重要的实体的主键。

  • 不只要关注MySQL,还要关注应用层优化:Apache服务器处理静态文件均可能使用一个占用内存很大的进程(上一个请求处理完后,该进程仍然保持着),因此最好使用Nginx或者Lighttpd来处理静态内容服务,并且静态文件名不要重用,要加上版本号,这样就能避免浏览器缓存问题;主动缓存如Squid,被动缓存如Memcached,均可以对性能得到数量级的提高,关键就在于找到正确的粒度和缓存过时策略组合,一般主动缓存更好,由于对应用层隐藏了检查-生成-存储这个过程;

  • ......

亮点太多,列不完了,须要你们本身去寻找。另外,这本书不适宜一次性的精读完毕(太厚,内容太多),能够快速浏览一遍,大概了解,之后赶上问题就能够把这本书看成一本问题解答手册来查询解决方案,或者找找灵感。

Redis实战

Redis实战 (豆瓣) https://book.douban.com/subje...

本书对redis的介绍是至关全面了,从基本用法讲起,而后讲了许多应用场景,包括购物车、数据库缓存等,而后讲了一些常见问题的解决办法,好比内存占用太高,自定义扩展来丰富redis的用法等等,看完一本书事后就能很好的使用redis了(还有本好书:redis设计与实现,我大体浏览了一下,这本书主要讲了redis的实现原理,这两本书加起来就能既懂原理又会使用,把redis搞个透彻)。

本书亮点:

  • 使用冒号 : 或者管道号 | 等来实现命名空间的做用,好比一个名为 article:12222 的hash存了这篇article的title,link,time等属性,article:12223又是另外一篇文章,这个能够部分实现数据库检索的功能。

  • 为了减小redis与客户端之间的通讯次数,能够用multi和exec来作事务处理,事务会一次性的把一批命令一次发给redis,提升吞吐率;另外事务还能保证一批操做的原子性。在node-redis实现中,若是只是想提升吞吐率则能够用batch替代multi。

  • 经过复制(主从)和AOF可以加强redis抵抗系统崩溃损失数据的能力,AOF若是用得很差的话,要么损失不少数据,要么严重下降吞吐量,比较合适的作法是appendfsync everysec 亦即把每一秒的命令一次同步进文件。

  • 使用 redis 的 setnx 来实现基本上正确的的分布式锁,再加上expire能够实现具备超时功能的锁,保证即便得到锁的客户端崩溃没有主动释放锁时,其余进程也有机会得到锁。

  • 用 list 来替代 subscribe、publish 实现更可靠的发布订阅系统;另外,利用subscribe、publish加list来实现具备离线缓存的消息队列系统,保证即便发生链接故障也能把消息送达。

  • 利用反向索引以及 redis 集合的并、交、差功能能够实现简易的搜索引擎,利用 hash 结构的 sort 功能还能对搜索结果进行简易的排序功能,利用有序集合 zset 能实现更高级的排序功能。

  • 社交网站一般是用时间线这一数据结构来实现新鲜事浏览这一功能,虽然致使了大量的冗余信息,可是可以节省查询时间,这是典型的以空间换时间的操做,我之前作社交APP后台的时候直接把全部新鲜事直接放在一张表中,而后按用户id查询,这样虽然省了空间,可是若是用户剧增((⊙﹏⊙)b,咱们的APP并无用户剧增)就不行了,一张表几亿行还怎么查。

  • 使用短结构来节约内存,使用较短的键名节约内存,分片下降单实例的内存占用。

  • 使用lua脚本,在不编写C代码的状况下,为redis添加新的功能。

时效性问题,本书没有一些最新特性 好比 geohash 解决了地理坐标问题,键的异步释放使得咱们能够放心删除而没必要担忧大量数据的删除使得redis短暂不可用。总之,要更好的利用redis仍是要追踪redis的最新变化,以便更简洁、更靠谱的解决问题。

深刻剖析Nginx

深刻剖析Nginx (豆瓣) https://book.douban.com/subje...

本书从源码入手,依次讲解了进程模型、模块、响应处理机制、过滤、负载均衡等相关原理,极大的知足了个人好奇心,由于以前一直就对nginx高并发处理能力有一丢丢了解(好比nginx采用事件驱动机制而非apache的进程、线程每请求方式),本身也用过nginx,可是对他的原理还不是特别的明白,本书算是填补了个人这个空白。

本书亮点:

  • Nginx 将职责分为监控进程(主进程)和工做进程(主进程fork的子进程),监控进程与用户交互并对工做进程进行监控管理,工做进程完成具体业务逻辑,二者都有一个无限的for循环,这是服务进程的基本写法。

  • Nginx仅提供针对大块内存的回收不提供小块内存的回收,这是由于web server的特殊性亦即阶段和时效,请求就申请内存,处理完毕就释放内存,因此不会存在nginx长时间占据大量无用内存的状况,那么小内存也天然没必要急于回收,而是成为大内存后在回收。

  • 对于客户端的请求,nginx将整个过程分为11个阶段,每一个阶段有数个回调函数进行专门的处理,每一个阶段的处理功能都比较单一,达到高内聚低耦合的目的。

  • Nginx是以事件为驱动的,也就是说Nginx内部流程的向前推动基本都是靠各类事件的触发来驱动,内部事件主要有两类:IO事件与定时器事件。其中IO事件主要靠epoll,epoll主要优势是监控数目不受文件描述符限制、事件响应是触发式的,不须要遍历描述符(select须要)。

  • Nginx要处理动态的内容通常须要转发给后端服务器,常见的搭配是nginx+fastcgi+php,nginx把http请求转化为fastcgi协议的数据后转发给PHP引擎,PHP引擎处理结果后把数据返回给nginx,nginx把数据转化为http格式返回给客户端。

  • 负载均衡有多重含义(或者说多重级别),能够是进程上的(根据master进程根据子进程压力调整其获取监听套接口的概率),更广的意义上是指反向代理上,亦即nginx把请求均衡的转发给后端服务器如PHP引擎,发挥多个单元的总体效能。通常采起加权轮询、IP hash等策略,可是只靠nginx是不能实现完整的负载均衡的,详见我之前写的一篇文章

这本书主要从应用及其原理方面来介绍nginx,对于后端程序员应该是够用了(我也忽略了许多源码,由于只是想了解一下原理)。可是对于要想本身深刻、进行模块编写的读者应该还不够用,能够再参考一下这本书 深刻理解Nginx(第2版)(我大概浏览了一下,本书会指导读者编写具体的模块及其底层原理,比咱们今天介绍的书更深刻一些)。

第一本Docker书

第一本Docker书 修订版 (豆瓣) https://book.douban.com/subje...

书如其名,这就是真正的第一本docker书。docker是什么、怎么安装、如何使用、测试集成、构建服务等都有介绍。以前就久仰docker大名,也试着试用了一下,可是直到这本书读完我才对docker有了一个完整的认知。另外,不出意料,本书的推荐序也很精彩。

本书亮点:

  • docker的核心价值在于可能改变软件的交付方式和运行方式。传统的交付方式下,软件运行期依赖的环境是没法控制,不能标准化的,开发人员经常须要解决开发环境和生产环境的差异带来的问题,而docker则把软件及其依赖环境打包在一块儿,以镜像形式交付,让软件运行在标准环境中,很是符合云计算的需求,同时docker的轻量虚拟化技术也符合实例水平扩展,资源动态调整的要求。

  • docker提供如下几个好处:简单轻量的建模方式,工程容易docker化,随时修改代码,运行快速;职责分离,开发人员只管开发,运维人员只管容器管理,减小环境不一样带来的问题;快速高效的开发生命周期,程序容易部署、移植和协做;容易实现面向服务的架构和微服务架构

  • docker只支持64位架构,原生的Linux容器格式:libcontainer,使用命名空间来隔离文件系统(每一个容器都有本身的root系统)、进程(每一个容器都运行在本身的进程环境中)和网络(容器间虚拟网络地址和IP地址都是分开的),使用cgroups将CPU内存之类的资源独立分配给容器,写时复制使得文件系统分层隔离、速度更快、占用空间更小,还提供日志和交互式shell。

  • 镜像分层:新镜像是从 base 镜像一层一层叠加生成的,文件系统发生变化时,就在现有镜像的基础上增长一层,这一层叫作“容器层”(读写层),“容器层”之下的都叫“镜像层”(只读层),只有当须要修改时才从镜像层复制一份数据到容器层,这种特性被称做写时复制(Copy-on-Write),达到了镜像共享,快速构建的目的。

  • 能够使用docker commit来构建镜像,也能够基于dockerfile和docker build命令构建,一般建议使用后者,由于dockerfile更具有透明性(能够清晰地看出安装了什么软件,修改了什么配置)、可重复性(一次编写,屡次使用。此外构建缓存还能够制做构建模板)、幂等性(同一个dockerfile不论执行多少次,结果都是相同的)。

  • docker容器之间通信有3种方式,1.9以前推荐用Docker Link(安全:只有link以前的容器能够通讯,没必要硬编码,不支持多主机),1.9以后推荐Docker Networking(支持多主机容器链接,能够热更新容器,Networking网络内部容器能够自主发现),不太推荐docker内部网络(IP硬编码等致使该方法不够灵活)。

  • volume(卷)具备一些有用的特性:容器之间共享数据,对卷的修改会直接反映在包含改卷的容器里因此能够在不修改容器的状况下向容器里加入、更新、删除数据,更新镜像时不会影响卷。利用这些特性能够更好的进行数据共享与持久化。

  • docker编排与集群化之路:Docker Compose 是用来作 docker 的多容器控制,使用Compose ,你能够在一个文件中定义多个容器应用,而后使用一条命令来启动你的全部应用,避免繁复操做,docker 自动化构建容器栈;Consul提供了一个易于使用,基于开放标准的服务发现解决方案,服务发现容许某个组件在想与其余组件通信时自动找到对方;Docker Swarm是一个用于建立Docker主机(运行Docker守护进程的服务器)集群的工具,使用Swarm操做集群,会使用户感受就像是在一台主机上进行操做亦即将容器抽象到集群级别。还有其余不少工具如:fleet、etcd、Kubernetes、Apache Mesos、Helios、Centurion。

时效性缘由,书中一些例子已通过时(如Docker1.12开始内置编排机制,Docker1.13正式支持docker stack),须要结合最新版本来使用。
另外,想要深刻理解docker能够阅读这本书 Docker——容器与容器云。我大体浏览了下,这本书不只讲了docker如何使用,还深刻讲解了docker的核心原理如namespace资源隔离、cgroups资源限制、libcontainer原理和一些高级实践技巧。此外,还讲了对容器、容器云的思考,包括如何构建本身的容器云,以及Kubernetes实现一切皆容器的“大同理想”。

UNIX/Linux 系统管理技术手册

UNIX/Linux 系统管理技术手册 (豆瓣) https://book.douban.com/subje...

又是一本进千页的大部头,可是不怕,这本书如其名,是一本手册性质的书,很是大而全,包括基本管理技术、网络管理技术和其余补充管理技术,几乎包揽了全部咱们可能用到的功能(小到一行代码整么写,大到数据中心怎么建),对于宏观把握整个Linux生态系统有很大做用。个人应对策略是跳跃式阅读(不错,就像上面那本MySQL),留下总体映像,等赶上问题时再来具体的查询相关部分的内容。也就是说,大脑至关于内存,书本至关于硬盘数据库,咱们首次阅读就是在内存中创建索引,便于提高之后的查找速度:-D。

本书亮点:

  • Linux各个发行版其实并无那么巨大的差异,咱们选择一个发行版时主要考虑几点:是否能长期存在,是否会有持续的安全补丁,是否会持续更新软件,发行商是否会在出了问题时帮咱们解决,不一样发行版侧重点会有所不一样咱们要根据本身的业务来进行选择。

  • 编写脚本时注意造成一种指导风格,这样你和你的团队成员能够按照相同的规范来书写代码,有了这种指导在阅读别人写的代码或者别人阅读你的代码时都会更容易;注释不要多也不要少,最好的效果是一两个月后再来读代码发现注释和有用。

  • 一个进程由一个地址空间(一组内存页面)和内核一部分数据(有关进程的信息如地址空间映射、状态、优先级、资源)组成;一个线程是在进程内执行fork的结果,继承了包含它的进程的许多属性,多个线程能够共享该进程内数据,并行(多核)或并发(单核,模拟并行)执行

  • Unix家族的文件系统目前没有一个标准,咱们尽可能按照以下标准来组织。bin:核心操做系统命令;sbin:系统最小规模运行所需命令;boot:内核及加载内核所需软件;etc:关键启动文件及配置文件;usr:次要的命令文件;var:随主机变化的文件如日志,数据文件;mnt:可移动介质临时挂载点;opt:可选的应用软件包;proc:正在运行的进程信息;tmp:临时文件;

  • 合适的备份计划取决于:文件系统的活跃性,转储设备的容量,用户指望的冗余度,想要购买的备份介质数量。

  • 版本控制与多人合做:svn是集中式的,一台中央服务器充当了一个项目的权威库;git是分布式的,没有中央库,每一个用户都含有一个完整的项目,采用的是拷贝-分支策略。

  • 信息安全领域的基本思想——CIA原则:Confidentiality(机密性),Integrity(完整性),Availability(可用性)。在设计、实现或者维护系统的时候,须要考虑CIA安全三原则,正如老话所说“安全性是一个过程”。

  • 负载均衡既提升了性能又增长了冗余性,包括几种方式:循环域名服务(也就是DNS轮询)、负载均衡硬件(好比Big-IP Controller、Content Services Switches等)、软件负载均衡(好比Nginx)。

  • Squid既是一个高速缓存软件也是一个代理服务程序,代理服务颇有用,可是Squid真正厉害之处是其高速缓存,它甚至可以造成一个缓存层次结构,以最大化提升缓存命中率。Squid是有意义的,由于用户对web的探索具备趋同性,因此在适度的规模上会出现至关多重复请求,运行高速缓存能够节省带宽和计算资源。

  • 虚拟化技术让多个彼此独立的操做系统同时运行在相同的物理硬件上,系统管理员把每一个虚拟机当作一台独立的服务器,既知足了软件厂商的要求,又下降了单一服务的成本。包括全虚拟化(如VMwareESX)、半虚拟化(Xen)、操做系统级别虚拟化(如workload partition)。除了传统的虚拟化技术,近年来的云计算也是一种(或者说类)虚拟化技术,它把计算能力做为对外提供的服务相似于水电等基础设施,直接使得硬件层对开发人员和系统管理员透明,提升了效率。

  • 分析性能问题步骤:明确表述问题、收集证据并分类、批判性的评价数据、用语言和图示总结证据、造成一份总结说明。这一套其实不止适用于性能分析问题,也适用于大多数其余问题,好比架构、重构、debug等等。

  • 系统管理不是一种行为艺术。不管作的什么,都应该能重复完成,切先后一致。一般意味着最底层的变化应该有脚本或者配置程序来作,而不是管理员来作。配置上的变化应该体如今系统管理软件的配置文件里。说白了,就是文档的重要性,在我看来:首先文档就是一家公司的财富,没有文档,人走了,那么以前公司的积累也就没了,又得重头来,损失很大;其次,文档是一种保证,你们都按约定办事,保证操做可重复,避免歧义与甩锅;再其次,文档能节约时间,虽然写的时候可能费点事,可是能节省后面大量的人员沟通的时间;最后,文档保证了系统的完整性,亦即文档保证了系统的后续修改遵循一致的思路和风格,才不至于系统随着时间流逝而愈来愈乱,难以维护与使用。

本书教会了咱们怎么使用Linux,这对于咱们后端开发人员是足够受用了。而这本书Linux内核设计与实现(原书第3版)就会告诉咱们Linux是如何实现它这么多这么强大的功能的内在原理,精力有限,我只是浏览了一下没有细读,等之后真的用得上Linux的深刻知识时,或者赶上了什么解决不了的问题,我会再来求助于这本书的。

代码整洁之道

代码整洁之道 (豆瓣) https://book.douban.com/subje...

本书提出一个观点就是:代码质量与整洁度成正比,围绕提升整洁度,做者展开了方方面面的阐述,从命名的方法到函数的定义,从注释的使用到格式的目的,还介绍了对象,错误处理等等等等。看完后的感受就是:写好代码,从本书开始。虽然我如今写的代码还比较“乱”,可是从此的代码中会努力践行书中的原则,争取写出整洁的代码。

本书亮点:

  • 软件质量既依赖于架构和项目管理,又与代码质量紧密相关,而代码质量与整洁度成正比,因此咱们要致力于写出干净整洁的代码。而且不只要知道书写整洁代码的原则,还有查看大量代码实例,进行案例研究,在实践中贯彻这些原则,才能真正作到知行合一

  • 不一样的人对整洁代码有不一样的理解,总归起来,有以下一些特色:代码逻辑直截了当,依赖关系不多,性能最优,每一个函数模块类专一于一件事,能够轻易的被其余人阅读,具备完整的测试,做者本身要在意本身的代码悉心维护,没有重复代码提早构建重复代码应有的抽象,体现系统的全部设计理念,包含尽可能少的实体。

  • 命名看似简单却无处不在,因此咱们不妨命好名,几个原则:名副其实,不用注释也能明白这个变量表明什么;避免误导,不要用保留词或太相同的词引发歧义;作有意义的区分,不要添加在名字后数字或者废话而是以读者能鉴别不一样之处的方式来区分;名字要读的出来,便于交流;名称要便于搜索;一个概念统一用一个词,好比不要混用manager和Controller;避免双关词;给名词添加语境,可是避免冗余的语境,含义明确的状况下,短名字老是比长名字好呀......

  • 函数构成了当今程序的基石,函数要写的明白要遵循以下原则:短小;只作一件事,也就是函数中的语句要在同一个抽象层级上,不在同一个抽象层级就得拆出来造成一个新的函数;把switch埋藏在较低的抽象层级,好比抽象工厂中,虽然依然免不了判断或者条件增多时要增添代码,可是可以把变化截留在工厂内,减小影响范围;不要向函数传入标志参数,好比TRUE/FALSE,而是应该直接把这个函数重构成两个函数;一个函数要么下达什么指令(set)要么回答什么问题(get),不要添加反作用;DRY(别重复本身)。

  • 注释是一种必须的恶,若是代码写的好根本不须要注释(感受有点过了,至少一个大的模块用来干啥仍是因该用注释或者说文档直接来讲明),并且代码才是真实的地方,注释极可能没有被维护而致使失效;别给糟糕的代码加注释,重写吧;版本控制系统能够帮咱们省掉许多注释如做者署名,注释掉的代码。

  • 或许你认为“让代码工做”是开发者的头等大事,可是其实并非这样的,代码风格关系着沟通,而沟通才是头等大事。代码风格影响着可维护性和扩展性,即便代码已不复存在,其风格和律条依然存在,于是一个团队应该造成一个统一的风格,便于沟通与维护。

  • 隐藏实现并不是就是简单的在变量之间放一个函数层。隐藏关乎抽象,类并非简单的用取值器和赋值器将变量向外推,而是暴露抽象接口,以便用户无需了解数据的具体实现就能操做数据自己。对象暴露行为,隐藏数据;数据结构暴露数据,没有明显的行为。要合理的利用两者。

  • 错误处理一旦处理很差就容易污染整洁的代码:使用异常来保证错误处理不会打乱正常的程序逻辑;可检异常可能会破坏开闭原则,要谨慎使用;打包第三方API就下降了对它的依赖;不要返回null值,只是忽然增长了工做量,能够用异常或者特例对象来代替。

  • 测试很是重要:测试代码和生产代码同样重要,脏测试就等于没测试;有了测试就能够毫无顾虑的进行重构和改善,由于有保证,消除了清理代码就会破坏代码的恐惧(这句话可谓是戳中了我,我以前的项目也有过一些重构的努力,可是就是怕重构事后不能正常运行,致使重构举步维艰);测试代码要清晰,符合构造-操做-检验三个环节;单个测试中的断言应该最小化,保证一个测试对应一个概念;整洁的测试遵循 FIRST 原则(fast,independent,repeatable,self-validing,timely)。

  • 系统层级的整洁:城市能有效运转是由于演化出了恰当的抽象层级和模块,有人负责全局有人负责细节,因此软件系统也有架构师和项目经理等;将构造和使用分开(依赖注入,控制反转);扩容(要考虑可扩展性,可是注重现有的系统的构造,未来再重构和添加,不必Big Design Up Front,考虑好模块化和关注切面划分就好)。

  • KISS(Keep It Simple, Stupid),简单设计原则:运行全部测试(测试是对一个系统的保证);不要重复(重复意味着额外的工做、风险、复杂度);表达了程序员的意图(清晰可读);尽量少的类和方法数量(避免教条如:每一个类都要有接口)。

  • 编程是一种技艺甚于科学的东西,不要期望一开始就写出优雅整洁的代码,通常是先写出肮脏的代码,而后进行重构,清理。因此代码仅仅能工做还不够,知足于代码能工做的程序员不够专业,他们惧怕没时间进行代码结构的从新设计,其实没有什么比糟糕的代码给项目带来更长远的损害了,糟糕的代码会一直腐败发酵,影响各个模块(找出这些依赖和影响至关不容易)无情的腐蚀整个项目和团队。

  • ......

这本书里面的良心建议实在是太多了,没法一一列举,真的得本身看一遍才能有收获。

重构-改善既有代码的设计

重构 (豆瓣) https://book.douban.com/subje...

上一本书教会咱们怎样书写整洁的代码,那么面对不整洁的代码,咱们怎么办呢?这本书就手把手教咱们怎么重构,改善现有的代码。从一个实例入手,讲了重构的理由、原则、技巧、步骤与时机。我读完事后感受内心就有了些烙印,不管是写代码仍是改代码,基本都会不自主的向这本书靠拢,颇有收获。

本书亮点:

  • 重构是在不改变代码外在行为的前提下对代码做出修改,以改进程序的内部结构,本质上说重构就是在代码写好后改进其设计,提升其可理解性,下降修改为本;记住全部代码的“坏味道”及其对应的重构手法,才能有信心面对各类状况——学会全部招式才可能“无招胜有招”;为了不自掘坟墓,重构必须系统化进行,用一些通过检验的重构手法,就能够一次一小步的修改代码,因此任何错误均可以比较容易的发现,下降了重构过程当中的风险。

  • 若是你发现本身须要为程序添加一个特性,而现有的代码结构使你没法方便的添加,那就先重构程序,使得特性添加变得容易,而后再添加这个特性。而重构的第一步就是创建一组可靠的测试,来尽可能避免bug,保证重构的正确性。

  • 对象A最好不要在另一个对象B的属性基础上使用switch语句,由于未来B变了A也必须变,若是不得不使用switch也要在本身的属性上使用,也就是把switch移动至B里面去;最好是用多态替换switch语句(其实也不是替换,而是把switch放在了较低的抽象层级,使得可能变化的部分就在一个对象里面,将其与不变的部分隔离开)。

  • 添加新功能和重构是两种行为,必定要加以区分,而且同一时刻只作好一件事就行。

  • 任何可以查询的东西,我都不太愿意去记,由于怕把大脑挤爆了。因此说大脑这个珍贵而有限的内存主要作的事必定是建好索引,而非存储数据;另外一方面,经常使用的数据也应该存进大脑,以提升效率,这和内存中的缓存是一个道理

  • 不要为了重构而重构,必定是由于你想作某件事时重构刚好能够帮你作好,重构的几个时机:添加新特性时,修补错误时,复审代码时。

  • 程序有两面价值“今天能够为你作什么”和“明天能够为你作什么”,若是只关注今天的工做,那么明天咱们将没法工做,因此须要重构,来避免代码出现如下四个状况:难以阅读,重复太多,新行为没法简单添加,逻辑复杂。这四个状况致使的结果都是程序难以改变(修改),而惟一不变的就是改变:-D

  • 代码的坏味道——重构的时机:重复代码、过长函数、过大的类、过长的参数列、发散式变化、霰弹式修改、依恋情结、数据泥团、基本类型偏执、switch语句、平行继承体系、冗赘类、夸夸其谈将来性、临时字段、过渡耦合的消息链、中间人、不适合的亲昵关系、殊途同归的类......

  • 本书给出了一份重构列表,包含了不少不少的重构类型的名称、动机、方法、范例,涵盖了函数、对象、数据、表达式、调用、归纳关系、大型项目等方方面面,值得咱们借鉴,下面摘抄几条做为示例。

  • 当我看见一个过长的函数或者一段须要注释才能让人理解用途的代码就会把这段代码放进一个独立的函数中。短函数的好处:更可能被复用,让高层函数看起来更清晰易懂,复写更容易。“短”的含义不在代码行数,而在于函数名称和函数本体之间的语义距离。

  • 若是一个类的某个方法、字段被另外一个类频繁使用,就应该搬移该方法、字段。

  • 混乱的继承体系是一个严重的问题,由于它会致使重复的代码,这正是程序员职业生涯的致命毒药。它还会使修改变得困难,由于特定问题的解决策略被分散到了整个继承体系,最终你的代码难以理解。因此能够经过创建多个继承体系,并利用委托来互相调用,使得原来负责多个任务的继承体系变成多个负责单个任务的继承体系。

  • ......

感受本书最大的问题就是太老了(1999年),有些工具或者方法在现在技术进步的状况下显得有些多余,好比如今的IDE如Eclipse或者IDEA都有很强大的功能,书里提到的一些技巧彻底用不着。不过经典终究是经典,里面的绝大部分思想咱们现在都仍是能够借鉴的,尤为是对于重复代码的观点——应该坚定消灭重复。

2017.9.8 后记

花费了几个月来看书,又花了几天来整理,但愿对咱们都有所帮助:-D。欢迎拍砖,个人主页Mageek`s Wonderland
查看原文

相关文章
相关标签/搜索