3

后端好书阅读与推荐

这一两年来养成了买书看书的习惯,陆陆续续也买了几十本书了,但是一直没有养成一个天天看书的习惯。今天突然想要做个决定:每天至少花1-3小时用来看书。这里我准备把这两年来看的书挑出好的做一个简要总结、即将要看的书做一个计划,以便整理成书单留给自己学习,也顺便推荐给需要的童鞋。

ps:本书单针对同一大类的知识点大致遵循着循序渐进,越学越深入越具体的顺序。

JavaScript高级程序设计

JavaScript高级程序设计(第3版) (豆瓣) https://book.douban.com/subje...

有人可能会有疑问,后端为啥要学JavaScript呢?其实就是为了更好的使用node.js做铺垫。这本书说是高级程序设计,其实还是比较基础,但是难能可贵的是它几乎包含了所有的基础知识,而且对基础知识的讲解比较深入,至少看了过后就不会犯那些常见的错误(比如for循环绑定变量i,这个问题几乎天天有人问(⊙﹏⊙)),能知其然、知其所以然,而且讲了许多最佳实践,所以还真的是高级。对于后端的同学可以只看基础部分,不看浏览器相关的部分(当然时间多也可以了解)。

本书有很多值得学习的地方,比如

  • 建议始终语句结尾要加分号,分支始终要加花括号,这样虽然多了些小麻烦,但能省去很多大麻烦:提高解析器性能,避免压缩错误,代码易读性可维护性更好。
  • 推荐使用 === 和 !== 而不是用 == 和 != ,这样才能保证代码中数据的完整性,避免歧义。
  • with语句不仅容易造成混淆,还会影响性能,不建议使用。
  • 函数按值传参,没有按引用传参,基本类型就不用说了,即使是引用类型参数a,函数也并不能修改a,使得a指向堆里面的另一个对象,所以也是按值传递。
  • 函数传参之时,使用对象字面量{}来封装大量的可选参数,比直接命名多个参数更灵活。
  • 函数声明才有提升,函数表达式不会提升。
  • apply 和 call 的作用是扩充函数赖以运行的作用域,使得函数和对象(调用者)解耦,从而可复用。
  • 构造函数与其相应的原型对象相互有指针指向,重写函数原型对象会切断已有对象与现有原型的联系。
  • 创建自定义类型时,构造函数放置实例属性,原型中放置共享的方法和属性,这样既保证了共享性,节约内存,也保证了私有性,达到封装的目的。
  • 利用惰性载入来提高代码执行效率。
  • 将一个函数中多次用到的全局对象保存为局部变量可以减少查询开销。
  • 变量和数组访问时O(1),对象属性访问时O(n)。
  • 减值循环优于加值循环,如果是大数据集,甚至可以展开循环来提升性能。

当然这本书也有点问题,主要就是时效性,本书主要按照ECMAScript 3 来讲解,最多提到了ECMAScript 5 但是现在都有ECMAScript 8 了,所以在看相关部分的时候,要注意查看最新的特性是否已经解决了某些问题(比如es8提出了Object.values 来直接获得对象的所有值而不需要先Object.keys,再来按key遍历),对本书要有所取舍(by the way ,几乎所有技术书籍,甚至我这篇文章,迟早都会有时效性问题,毕竟我们处于一个变化巨大的时代,但这并不影响它们成为经典,只要我们有所取舍,取其神,去其形即可)。

深入浅出Node.js

深入浅出Node.js (豆瓣) https://book.douban.com/subje...

和一般的讲node的书不同,这本书不是简单的讲一讲怎么使用npm,用一用express或者连一连mysql这样的API文档式书籍,而是真正的深入浅出,本书首先介绍了node的来源,用处,让我们知道它存在的意义,然后依次介绍了模块机制,异步IO的实现,异步编程的解决方案,内存控制,buffer,网络编程,web应用,进程管理,测试,产品化。

本书的优点相当多:

  • 对于异步IO的阐释相当深入,首先阐释了node是单线程的,能避免死锁,同步等问题,而其异步IO在内核中本质上是用了线程池,也能达到充分使用多核的效果,提升吞吐量。
  • 对于异步编程这个痛点作者提到了发布订阅模式,Promise,以及各种流程库,更赞的是作者自己还写了个库EventProxy,我自己用过,可以说是非常好使的。这一章帮助我们很好的解决了深度嵌套的问题。
  • 内存控制讲到了分代垃圾回收机制,V8把内存分为新生代和老生代,新生代采用空间划分(from、to)和复制机制来回收非存活对象,若新生代对象在多次复制后依然存活,则移动至老生代,老生代采用标记清除和标记整理的做法。这种针对不同代使用不同算法的做法能够到达效率最优的效果。同Java一样,垃圾回收时也会stop the world,所以要尽量避免(虽然老生代采用了增量标记、延迟清理、增量式整理来减少停顿时间)低效或者频繁的垃圾回收,比如要主动释放变量,减少使用闭包等。
  • Buffer可以解决数据拼接时的中文乱码问题;直接使用buffer来进行IO,网络传输可以提高吞吐量。
  • 采用多进程来最大化利用内核的资源,句柄传递达到多进程监听同一端口的目的。
  • 把静态资源交给nginx等服务器或者CDN来处理,能提高性能。

本书的不足之处可能在于组织上吧,感觉有点头重脚轻,比如对于初学者来说,一般想先看看node如何做web,或者做网络服务,体验点成就感,然后才是学习其实现原理,而本书反了过来;而对于进阶者来说,后面的web、网络服务部分似乎浅的有点用不上,有点鸡肋(⊙﹏⊙)。但是我们可以根据自己的需要有选择的进行章节阅读,就能避免这个问题。

Java编程思想

Java编程思想 (第4版) (豆瓣) https://book.douban.com/subje...

本书可谓是经典了,它不是基础知识面面俱到的入门书籍(Java核心技术·卷1:基础知识(原书第9版) (豆瓣),这本书就讲全了基础知识,而且不是浅尝辄止,还进行了深入探讨,所以也推荐),而真的是如翻译的书名一样,体现了Java的思想,是Java中一些精要的集合,我们不必按照作者的顺序去阅读,可以根据需要选择性的阅读。本书还融合了许多设计模式,需要我们去感悟其中的思想。

这本书比较精彩的部分:

  • 把面向对象编程人员分为两类:“类创建者”(创建新数据类型的人)以及“客户程序员”(在自己的应用程序中采用现成数据类型的人),前者负责构建类,只开放必要的东西而隐藏其他细节(开放封闭原则),后者负责搜集这些类来完成特定任务。
  • 需要采取一种最适合自己需要(以及习惯)的方法来制定计划。不管制订出的计划有多么小,但与完全没有计划相比,一些形式的计划会极大改善你的项目。
  • 首次创建对象或者访问该类的静态字段、方法时会初始化这个类,static初始化仅在第一次运行,其它字段每次创建对象都会运行,我这里顺便总结一下对象的初始化过程:

       (1) 主类的每一个父类由高到低按顺序初始化静态成员及其静态初始化块,无论静态成员是否为private。 
       (2) 主类静态成员的初始化,静态初始化块的初始化。
       //创建实例时,如果不创建实例,则后面的不执行 
       (3) 主类的父类由高到低进行默认构造方法的调用。在调用每一个父类的默认构造方法前,先进行对此父类进行非静态成员,
       非静态初始化块的初始化。  
       (4) 主类非静态成员的初始化,非静态初始化块的初始化。 
       (5) 调用主类的构造方法。
       
  • final的引用类型变量本身是不可变得,但是其引用的对象是可变的(数组也适用这个规则),所以不要期望能够一步达到一个常数对象的效果
  • 方法代码少或者想禁止覆盖时使用final方法能够得到一定程度的性能提升。
  • 将一个方法调用同一个方法主体连接到一起就称为“绑定”(Binding)。若在程序运行以前执行绑定(由编译器和链接程序,如果有的话),就叫作“早期绑定”,“后期绑定”,它意味着绑定在运行期间进行,以对象的类型为基础。后期绑定也叫作“动态绑定”或“运行期绑定”。Java 中绑定的所有方法都采用后期绑定技术,除非一个方法已被声明成 final。这意味着我们通常不必决定是否应进行后期绑定——它是自动发生的。
  • Java 包含了一个名为 Throwable 的类,它对可以作为违例“掷”出的所有东西进行了描述。Throwable 对象有两种常规类型(亦即“从 Throwable 继承”)。其中,Error 代表编译期和系统错误,我们一般不必特意捕获它们(除在特殊情况以外)。Exception 是可以从任何标准 Java 库的类方法中“掷”出的基本类型。此外,它们亦可从我们自己的方法以及运行期偶发事件中“掷”出。
  • 对于作为程序一部分的每个类,它们都有一个 Class 对象。换言之,每次写一个新类时,同时也会创建一个Class 对象(更恰当地说,是保存在一个完全同名的.class 文件中)。在运行期,一旦我们想生成那个类的一个对象,用于执行程序的 Java 虚拟机(JVM)首先就会检查那个类型的 Class 对象是否已经载入。若尚未载入,JVM 就会查找同名的.class 文件,并将其载入。

如上所述,本书也有时效性问题,所以要配合最新的Java8甚至Java9来查阅;同时,本书的代码实在是太多,有些可以忽略不看,并不影响理解。
本书作为一本整体大致地把握Java的书籍是合适的,但是Java实在是太大了,要真正细致的掌握每一个知识点比如多线程、网络编程、Spring,还得看专门的书,比如下面要讲的这本。

Java并发编程实战

Java并发编程实战 (豆瓣) https://book.douban.com/subje...

本书从并发性和安全性的基本概念入手逐步深入,讲到用类库构建线程安全类,然后讲到了如何利用多线程来提升吞吐量,Java中的一些现有多线程框架的使用,性能测试,最后讲了显示锁,原子变量等进阶知识点。基本囊括了能用到的多线程所有知识点。

本书亮点:

  • 线程安全性定义:当多个线程访问某个类时,这个类总是能表现出正确的行为。线程安全类自己封装了必要的同步机制,调用者无需再进一步采取同步措施。无状态的对象一定是安全的。
  • 并发编程由于不恰当的执行时序造成错误叫做竞态条件,最常见的就是先检查后执行的操作,比如i++就是典型的例子,
  • 无状态的类添加一个状态,若该状态线程安全,则这个类也安全,但是若添加了多个状态,仅仅是每个状态线程安全还不够,还需要保证单个操作中同时更新所有状态(如果每个状态都是独立的就不必)
  • 内置锁是可重入的,这意味着获取锁的粒度是线程而不是调用,也就是说锁和一个线程对应。
  • 加锁机制可以保证可见性和原子性,而volatile只能保证可见性
  • ConcurrentHashMap采用了分段加锁的机制来实现更大程度的共享,任意数量读线程可以访问Map,一定数量的写线程可以并行修改同一个Map,一般情况只有在需要独占访问Map时才应该放弃使用ConcurrentHashMap。
  • 使用tryLock来替换会永远等待的内置锁,这样就能消除死锁发生的可能性。
  • 确保线程在获取多个锁时才用一致的顺序,也能避免一些死锁。
  • 不应当依赖于线程优先级来实现业务逻辑,因为这与平台有关,不能得到保证。
  • 避免不成熟的优化,首先使程序正确,必要时再提高运行速度-如果嫌它不够快的话。
  • 使用并发安全的容器类、读写锁、不可变对象、原子变量等来替换独占锁,提高吞吐量。
  • 使用显示锁时,要在finally中释放,因为它不会像内置锁一样自动释放。
  • 一般情况下公平锁(先到先得)会比非公平锁的性能低得多(数倍,数十倍),不必要的话不要用公平锁,非公平锁在统计意义上是公平的,就够用了,而且ReentrantLock 默认就是非公平的,内置锁也是。

如上所述,本书时效性也有问题,主要用的是Java5,6,所以也要注意查阅最新文档对比(实战Java高并发程序设计 (豆瓣) https://book.douban.com/subje... 这本书在时效性方面就要强一些,讲到Java8了,而且也比较通俗易懂,推荐~),另外,Swing那一段可以跳过不看了。

Java Web高级编程

Java Web高级编程 (豆瓣) https://book.douban.com/subje...

这本书的强大之处就在于一本书几乎包揽了java web 所有的主流技术,所谓此书在手,Java我有(⊙﹏⊙)......开个玩笑,本书非常大非常厚,所以也非常全,所以我也并没有看完,但是我看过的部分真的让我认为这是一本好书。本书从servlet原理讲起,讲到jsp,一步步讲到Spring,过度很自然,让人明白Spring存在的理由,然后讲了Hibernate(虽然我没看),最后讲了Spring security,可谓一气呵成,同时又不失条理,系统性很强,看完之后对于Java web 应该能有个整体的把握。

本书亮点:

  • 多使用jdk7的try with source ,它会帮助自动释放资源,减少错误。
  • Java EE 一般采用子女优先类加载方式,Java SE 一般采用双亲优先类加载方式。
  • Servlet是所有web应用程序核心类,它是唯一即可以直接处理和响应用户请求又可以将处理工作委托给其他部分的类。java EE 7 唯一支持的Servlet协议就是http。
  • 表示层与业务层应该分开,所以jsp中不应使用Java代码,而且jsp表达式EL本身已足够强大。
  • Controller依赖于Service,Service依赖于Repository,Repository依赖于数据库,这四者就像食物链中的肉食者,杂食者,植物,大自然。不同于传统MVC架构,这种架构中Service才是真正的业务逻辑,Controller是负责不同的页面逻辑,比如web页面和移动应用的API,这种架构能够复用真正的业务逻辑,优于MVC。

我感觉这本书唯一的缺点就是太厚了吧:-D,会吓跑许多人(包括我)。

Head First 设计模式

Head First 设计模式(中文版) (豆瓣) https://book.douban.com/subje...

这本书最大的特点就是不拘一格讲知识,他不会板起脸来告诉你这个叫观察者模式,那个叫装饰器模式......而是通过一些通俗易懂的例子(会飞会叫的鸭子,气象站检测应用的建设)和丰富的图例、游戏(运用了认知科学的方法)来说明不同的设计模式的含义、用途、优点和缺点,使人印象深刻,容易理解和记忆。

本书展示了很多有意义的设计原则,比如:

  • 封装变化,即找出应用中的变化之处,把他们独立出来,不要和不变的代码混在一起。所以设计系统之时就要开始考虑可能变化的东西把它隔离出来,并且在做的过程中可能会需要重构,毕竟唯一不变的就是变化。
  • 针对接口编程,而不是实现编程。也就是变量的声明应该是超类型,这样执行时就会根据实际情况执行到真正的行为,而不必绑死在超类的行为上。
  • 多用组合,少用继承。组合比继承具有更大的灵活性和更稳定的结构,只有当确实是 is-a 的时候才应该使用继承
  • ......

对于设计模式初学者来说,这本书似乎比四人组的设计模式更容易接受,因为它不是那么严肃,不是那么学究,当然如果希望严肃的学习,或者本身水平较高,那还是看四人组的比较好~

程序员修炼之道

程序员修炼之道 (豆瓣) https://book.douban.com/subje...

本书可以说是一本学习方法论,或者工作方法论的书,再高一点可以说是一本哲学的书。本书原名The Practical Programmer,亦即注重实效的程序员,全书围绕注重实效展开讨论,包括注重实效的哲学(负责,变化,权衡,管理知识,交流)、途径(避免重复,随时记录,估计)、工具(文本,shell,游戏,源码控制)、偏执或者说讲究(规范合约、断言、异常使用)等等等等。

本书从推荐序开始就相当精彩:

  • 如果仅仅以普通的浏览方式阅读就会很简单的陷入“啊,这个我知道啊,啊,这个我了解啊,嗯,这个以后要注意”的套路中。这样的阅读方式只会强化原有的自己知道的知识,而不大可能把“以后需要注意”这部分全部内化。所以自负的读者读完必然觉得“哈哈,高手不过如此,大部分我也知道嘛”,而不是“是的,我还有不少要注意”。这一段可谓是抓住了我的一个大毛病,我以前看完书老是觉得啥都懂了,可是真开始做还是一脸懵逼,这就是为啥我们上学都有作业做的原因,体会很深刻啊
  • 定期为你的知识资产投资,比如每年学习一门新的语言来拓宽思维,每季度读一本书(是不是有点少:-D)。
  • 不要重复自己,重复是维护的灾难(因为你可能根本记不住哪里还用了这个东西)。
  • 估算,以避免意外。学会估算,并发展到对事物的数量级有直觉的程度,就能更好的确定任务可行性。
  • 按合约设计,这样才能明确责任和权利,解决与人打交道的问题。说实话,做了两个小项目我就真的体会到了这一点的重要性,没有文档,没有合约,只会导致进度拖拉,到处甩锅,军心不稳
  • 分析工作流,以改善并发性,这样确定哪些任务可以并行,哪些不可以,从而更合理的安排,加快进度。当然这是属于较大的任务的处理方法,小任务有这些分析的时间我都做完了

本书读起来可谓非常畅快,但是要落实真的是不容易,而且我觉得应该反复读,因为每增加一些工作经验就会遇到一些问题,对书里面提到的要点也就感悟更深,从而能更好的解决问题。

架构即未来

架构即未来:现代企业可扩展的Web架构、流程和组织(原书第2版) (豆瓣) https://book.douban.com/subje...

这本书乍一听可能会觉得它是讲的架构是诸如MySQL 读写分离,redis cluster,CDN,负载均衡等架构问题,看完绪论和第一章才发现不是那么回事(⊙﹏⊙),原来它前面很大的篇幅都在讲人事上的架构,后面才是技术上的架构,会不会有种受骗的感觉?其实不必,这本书相当于是站在了更高的角度来看问题,毕竟要把技术上的事做好做大都离不开强大的团队,离不开完善的人事管理。

结构上本书分4部分:团队的组织、管理和领导,构建可扩展技术平台的方案与危机管理,可扩展的架构方案,新的趋势如大数据云计算等的架构。

我感觉比较精彩的一些点是:

  • 如果汽车没有油量表和速度表,大多数人都不会考虑开这种车,同理,系统也需要一系列指标帮助我们达到希望的结果。
  • 管理是推,领导是拉。领导设定目的地和路线图,管理设法达到目的地。
  • 责任不清,则意味着有些事没人去做,或者一件事被多个人做了,直接后果就是进度拖拉,效率低下。当你在定义一个组织的角色和责任时,就是在设计一幅权力下放的蓝图。
  • 对团队而言,少于6人就没必要单独成为一个团队,超过15人经理管理会产生困难,成员之间沟通也会更困难,所以一个团队的人数要根据经理的能力,人员熟悉程度,要实现的目标来共同制定。
  • 总体而言,相信自己被赋予权力的个人会比那些相信自己只是在执行命令的人会有更高的效率,在我理解来就是主观能动性更高,有了主人翁意识(ownership)自然就会尽力去把事情做好,而非仅仅是打工仔:-D。
  • 架构原则:监控设计能使我们进行自我修复自我诊断,在用户发现问题前就解决问题;多活数据中心可以达到负载均衡和容灾的目的;使用成熟的技术,谨慎的在线上系统采用新技术,因为通常有较高的故障率,我们一般可以自己先做许多的试用,再决定是否使用;水平扩展而非垂直扩展,亦即系统扩展性依赖于更多的机器而非更强大的机器。
  • ......

2017.8.3 后记

7.26 就开始着手写了,但是为了能更好的总结这些书,我又把它们全部过了一遍然后才写,直到 8.3 才写完,希望能起到一些作用。后面我还会持续更新更多的好书,会涉及到Linux、Jvm、Redis、MySQL、Docker等,欢迎拍砖交流,我的主页 - Mageek`s Wonderland http://mageek.cn/archives/33/



MageekChiu
4.4k 声望1.7k 粉丝

T