专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序员小灰  ·  部署DeepSeek ... ·  12 小时前  
程序员小灰  ·  小灰筹划6年的“仓鼠币系统”,终于上线了! ·  2 天前  
程序员的那些事  ·  快!快!快!DeepSeek 满血版真是快 ·  2 天前  
OSC开源社区  ·  Bun ... ·  2 天前  
程序员的那些事  ·  OpenAI ... ·  3 天前  
51好读  ›  专栏  ›  SegmentFault思否

后端好书阅读与推荐

SegmentFault思否  · 公众号  · 程序员  · 2017-09-18 08:00

正文

续前文 后端好书阅读与推荐 - Mageek`s Wonderland ,几十天过去了,又看了两本好书(还有以前看过的书),这里依然把它们总结归纳一下,加入一些自己的看法、有用的链接和可能的延伸阅读,并推荐给需要的同学。

《深入理解Java虚拟机》

https://book.douban.com/subject/6522893/

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

本书亮点:

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

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

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

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

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

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

  • 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》

https://book.douban.com/subject/23008813/

这本书可谓是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实战》

https://book.douban.com/subject/26612779/

本书对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》

https://book.douban.com/subject/23759678/

本书从源码入手,依次讲解了进程模型、模块、响应处理机制、过滤、负载均衡等相关原理,极大的满足了我的好奇心,因为之前一直就对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书》

https://book.douban.com/subject/26780404/

书如其名,这就是真正的第一本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 系统管理技术手册》

https://book.douban.com/subject/10747453/

又是一本进千页的大部头,但是不怕,这本书如其名,是一本手册性质的书,非常大而全,包括基本管理技术、网络管理技术和其他补充管理技术,几乎包揽了所有我们可能用到的功能(小到一行代码整么写,大到数据中心怎么建),对于宏观把握 整个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/subject/4199741/

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

本书亮点:

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

  • 不同的人对整洁代码有不同的理解,总归起来,有如下一些特点:代码逻辑直截了当,依赖关系很少,性能最优,每个函数模块类专注于一件事,可以轻易的被其他人阅读,具有完整的测试,作者自己要在乎自己的代码悉心维护,没有重复代码提前构建重复代码应有的抽象,体现系统的所有设计理念,包含尽量少的实体。

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

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

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







请到「今天看啥」查看全文