《架构整洁之道》读后感

前言

昨晚(2020年4月24日)看完了《架构整洁之道》,这应该是我读的第一本Bob大叔的书。其中使我印象深刻的并不是那些所谓“新瓶装旧酒”的技术知识,毕竟写过几年代码的人,应该早在其他地方学习过这些知识了。真正让我印象深刻的是,不论时间和空间存在着多大的差异,面对着同样的问题,“猿类”都有着类似的思考过程。


内容概括

对于技术内容的详细回顾,还是直接看阿里巴巴的总结吧。

阿里巴巴——架构整洁之道, 看这一篇就够了!

从目录来看整体的内容:

  1. 概述
  2. 编程范式
    • 结构化编程:结构化编程对程序控制权的直接转移进行了限制和规范。
    • 面向对象编程:面向对象编程对程序控制权的间接转移进行了限制和规范。
    • 函数式编程:函数式编程对程序中的赋值操作进行了限制和规范。
  3. 设计原则(SOLID原则)
    • SRP (Single Responsibility Principle) 单一职责原则:每个软件模块有且只有一个需要被改变的理由。
    • OCP (Open Closed Principle) 开闭原则:允许新增代码来修改系统行为,而非只能靠修改原来的代码。
    • LSP (Liskov Substitution Principle) 里氏替换原则:组件必须遵守同一个约定,以便让这些组件可以相互替换。
    • ISP (Interface Segregation Principle) 接口隔离原则:避免不必要的依赖。
    • DIP (Dependence Inversion Principle) 依赖反转原则:实现底层细节的代码应该依赖高层策略性的代码。
  4. 组件构建原则
    • 组件聚合
    • 组件耦合
  5. 软件架构
    • 整洁架构
  6. 实现细节
    • 数据库只是实现细节
    • Web是实现细节
    • 应用程序框架是实现细节

摘抄

问题就像有一个生命体一样,它们会不断地繁殖和进化。

大多数人的目标不是设计出一个优质的软件或架构,而是快速地解决一个具体的问题,完成自己的工作。

所谓软件架构,就是你希望在项目一开始就能做对,但是却不一定能够做得对的决策的集合。 ——Ralph Johnson

软件架构是一个猜想,只有通过实际实现和测量才能证实。 ——Tom Gilb

走快的唯一方法是先走好。 ——Robert C. Martin

软件架构的终极目标是,用最小的人力成本来满足构建和维护该系统的需求。

“我们可以未来再重构代码,产品上线最重要!”但是结果大家都知道,产品上线以后重构工作就再没人提起了。

胡乱编写代码的工作速度其实比循规蹈矩更慢。

业务部门原本就是没有能力评估系统架构的重要程度的,这本来就应该是研发人员自己的工作职责!

研发团队必须从公司长远利益出发与其他部门抗争,这和管理团队的工作一样,甚至市场团队、销售团队、运营团队都是这样。公司内部的抗争本来就是无止境的。


片段感想

事件溯源

只存储事务记录,不存储具体状态。当需要具体状态时,只要从头开始计算所有的事务即可。

应用程序不提供完整的CRUD,只提供CR。说实话,基于某个政府项目的需求,我真的有在实际项目中考虑过这种实现方式,不过由于我无法解决性能方面的问题,就此作罢了。

这种实现方式听起来的确不太靠谱,但Bob大叔指出“源代码管理程序”的时候,令我醍醐灌顶。不过,话说回来,演算这种做法被我放弃后,用户的需求可没变,最后还是采用了另外建立一张日志表来记录变化的做法。


实现细节

  • 数据库只是实现细节
  • Web是实现细节
  • 应用程序框架是实现细节

这句话让我想起刚毕业找工作时的场景,我带着毕业设计(一款局域网直播软件)四处面试,其中的一间公司的某位面试官,在看了我的简历和作品后,首先是质问我为何没有用数据库,然后慷慨激昂的向我普及了数据库的重要性。听罢令我十分羞愧,似乎没有使用数据库,我就犯了原则性错误一样。这一度让我怀疑自己的价值,也怀疑那张省级优秀毕业论文奖状的价值。

也不记得多久之后就释怀了,用了多么优秀或者多么适合的工具,并不能彰显自己的核心价值,解决了问题才有核心价值。用数据库存储数据还是直接读写文件,都只是实现细节,不影响软件的核心直播功能。我很感激那位面试官,面对着一位已经被淘汰的面试者,仍愿意分享自己的经验,尽管语气强烈了一点。


业务逻辑

业务逻辑是一个软件系统存在的意义,它们属于核心功能,是系统用来赚钱或省钱的那部分代码,是整个系统中的皇冠明珠。

之前持续了很长一段时间,特别喜欢搜集一些工具类(Utility Class),例如DbHelper。自己也曾一度沉迷于写这些工具类,就像给自己准备了一堆像锤子、起子、螺丝刀、钳子和扳手之类的工具,似乎有了这些储备,就能在以后的代码之路披荆斩棘一般。可实际上,这些工具类代码,使用的频率低的可怕,绝大部分代码基本写出来后就再没看过。

每一个让我花费大量精力和时间的项目,都是在梳理业务逻辑(当然这里包括了解用户需求),用代码实现这些逻辑相比之下倒成了相当轻松的事情(再次当然,我目前接触到的项目,的确也用不上很尖端的技术水平)。


Web是实现细节

20世纪90年代的时候,你已经是程序员了吗?还记得Web是如何改变一切的吗?你记得我们在有了崭新的Web技术之后,是如何鄙视那些老旧的客户端/服务器架构的吗?

然而,Web技术事实上并没有改变任何东西,或者说它也没有能力改变任何东西。这一次Web热潮只是软件行业从1960年来经历的数次振荡中的一次。这些振荡一会儿将全部计算资源集中在中央服务器上,一会儿又将计算资源分散到各个终端上。

事实上,在过去十年内,或者说自Web技术被普遍应用以来,这样的振荡也发生了几次。一开始我们以为计算资源应该集中在服务器集群中,浏览器应该保持简单。但随后我们又开始在浏览器中引入 Applets 。再后来我们又改了主意,发明了 Web 2.0,用 Ajax 和 Javascript 将很多计算过程挪回浏览器中。我们先是非常兴奋地将整个应用程序挪到浏览器去执行,后来又非常开心地采用 Node 技术将那些 JavaScript 代码挪回服务器上执行。

一声叹息!

读到这里不禁笑出了声,话说天下大势,分久必合,合久必分,软件行业也难置身事外。

云计算、边缘计算等概念层出不穷,现在各种3A大作,是越来越吃电脑性能了,CPU、显卡、内存、硬盘,是一个都不放过,为了玩这类游戏,掏钱买个正版还只是拿了张门票。

就拿云游戏举个例子,游戏在云端运行,本地只处理IO,我实际体验了一番,效果的确不错,但游戏体验,就受限于网络水平和服务公司的收费水平了。

本地只处理IO这个概念,在网页应用上体现得更为彻底,例如网页版office,使用体验不亚于桌面版office,但万一断网,那就无计可施了。

就像CAP的三选二的理论一样,这个世界不存在完美的解决方案,无论什么方案都有好的一面和不好的一面。 ——陈皓(@左耳朵耗子)


本书拾遗

这一章的中心思想就是,如果不考虑具体实现细节,再好的设计也无法长久。必须要将设计映射到对应的代码结构上,考虑如何组织代码树,以及在编译期和运行期采用哪种解耦合的模式。保持开放,但一定要务实,同时要考虑到团队的大小、技术水平,以及对应的时间和预算限制。最好能利用编译器来维护所选的系统架构设计风格,小心防范来自其他地方的耦合模式,例如数据结构。所有的实现细节都是关键的!

纸上谈来终觉浅,绝知此事要躬行。再美好的想法,能踏实落地才算。


后序

我的软件工程师生涯开始于20世纪90年代,那是一个恐龙级大型架构统治世界的时代。要想在那样的时代获得一席之地,我们必须学会对象及其组件、设计模式、统一建模语言(包括其前身)的相关知识。

现在想起来,或许真的可以考虑把我们那段日子所做的事情叫做 “童子军项目” 。每个项目的开头都会有一段长长的设计阶段,以便那些 “高级” 程序员为一些跟随他们的、较 “低级” 的程序员制订好系统的设计蓝图,当然,这些“高级”程序员似乎永远完不成这件事。

于是乎,做这件事的人被升级到了 “软件架构师” ,接着是 “首席架构师” “总架构师” “枢密院首席架构师” 以及其他各种高不可言的头衔,最终,我们还是让一切回到了原点。而我似乎注定要把时间花在画那些带箭头的盒子和编写 PowerPoint 的事情上,而这些事对真实代码的影响近乎为零。

这让我无比受挫,每一行代码本身都至少包含了一条设计决策,任何一个写代码的家伙对软件质量的影响都远在我这个 PowerPoint专业户之上。

幸运的是,接下来发生的敏捷软件开发革命终于让我们这些架构师脱离了苦海。毕竟我是一名程序员,喜欢的是编程。而且我也发现影响软件质量最好的方法还是编写代码。

这些大型架构像恐龙一样在大进程式的原始平原上游荡,然后被一颗叫做 “敏捷开发” 的小行星灭绝了,真是老天开眼啊!

现在,开发团队们可以自由地专注于真正重要的内容,并思考如何为他们所做的事情添加更多价值了。也就是说,他们现在再也不需要浪费几周或几个月的时间等待那些大型架构的设计文档了,他们可以名正言顺地忽略这些设计,直接按照自己的想法编写代码。然后,开发团队只需要安排客户直接参与测试,并在快速设计会议上得到用户的支持,然后他们就可以继续写代码了。

大型架构像恐龙一样消失了,前期设计够用、后期进行大量重构的设计思想和小巧玲珑的哺乳动物一样代替了它们,软件架构迎来了响应式设计的时代。

好吧,无论如何,以上这些都属于理论。

我此刻便是终日画那些带箭头的盒子和写PPT,如果我对代码亲力亲为,还会受到领导的批评,😂。敏捷开发这个概念,至少领导听过,尽管领导并不理解,仍旧要求我们按照那本二十多年前的《软件工程导论》严格执行。在这里,我不是说《软件工程导论》写得不好或内容过时,对于小公司而言,涉及到公司管理问题,😶私以为,写文档还是比敏捷开发靠谱多了。

但终究还是要做正确的事情,走上正确的道路。如果说博士是突破知识的边界,提升上限水平,那是谁在提高下限水平呢?应该就是政府吧。


感想

整本书读完,犹如和一位老友相谈甚欢,只惜相见太晚,不过,也正如陈皓在序言里所写:

我个人觉得,这本书是架构方面的入门级读物,但也并不适合经验不足的人员学习,这本书更适合的读者群是,有3~5年编程经验、需要入门软件设计和架构的工程师或程序员。

此刻的相遇,却也恰好是感悟最深的阶段,幸甚至哉。

那么,全书在我看来,就是在告诉我,对于软件开发而言,什么是重要的事情,软件的核心价值在哪里。

在这里,引入《计算机组成原理》的知识来举例,典型的冯·诺依曼计算机结构里,是以运算器为中心,四周辅以控制器、存储器、输入设备和输出设备,那么类比到软件,业务逻辑便是中心,软件框架、数据库、Web或GUI或命令行都只是辅助。

墨客在面对着大好河山,他想要一支笔,你却给他一把杀猪刀,可谓冬扇夏炉。软件是要用来解决问题,而不是单纯用来炫技的,这也大概就是算法为什么这么重要了吧。

可话又说回来,《计算机组成原理》里紧接着就表明,现代的计算机是以存储器为中心的,那类比过来是不是说数据库是最重要的呢?我认为不是,这需要从另一个角度来看。举个简单的算法例子,如何判断一个数是否为质数,尽力降低时间复杂度和空间复杂度才是这个问题所要研究的,但是在限定范围内,打表才是最优的解决方案。祖冲之可能穷极一生“也才仅仅”算到圆周率的第七位,以存储器为中心的概念,不是指这七位数字的重要性,而是记录传承前人所做的研究的重要性,文化如果无法传承,那生存也就没有意义了吧。所以,以存储器为核心,我觉得应该是认可数据的价值,而不是容器的价值。

这也就很自然的引入了另一个问题,是不是一款软件只需要把业务逻辑(或者叫核心算法)做好,其他部分就可以从简呢?我觉得那也不是,毕竟软件还是要讲用户体验的,这大概就是Linux系统在个人使用领域一直都干不过Windows的原因吧。

达则兼济天下,穷则独善其身。站在顶峰的人,应该不仅仅是为了解决眼下的问题,更多的是解决未来的问题,他们的研究成果可能需要数十年甚至几代人的传承后才得以绽放光芒。而我,还是先坚持公司“以客户为中心”的经营理念来解决温饱问题吧。


后记

易读、可扩展、可维护、可重用的代码。

简单 vs. 简陋、平衡 vs. 妥协、迭代 vs. 半成品

普通程序员 -> 工程师 -> 架构师

光阴荏苒,日月如梭,本猿的进化之路依旧望不到头,达尔文可否放我一马?