2021年8月

《架构整洁之道》是Uncle Bob|Bob大叔【美】Robert C. Martin(罗伯特 C. 马丁)在2017年写的介绍软件架构的书。本书从最细节的编程范式,再讲到SOLID设计原则,然后依次介绍高阶的组件、软件架构。后面强调了数据库、框架、Web等是实现细节而非架构。最后则是其他人写的拾遗和半工作经历自传。整本书有点像搭建房子时介绍建筑架构,先从砖和钢筋混凝土到房价再到房子等由小到大介绍开了,很有趣。

作者总结了3中编程范式:

  1. 结构化编程:最传统的,程序是欧几里得公理系统;对函数控制权的直接转移进行了限制和规范;
  2. 面向对象编程:通过封装、继承和多态,对程序控制权的简介转移进行了限制和规范;
  3. 函数式编程:通过变量不可变(函数无状态)、对可变进行隔离,对程序中的赋值进行了限制和规范。

作者总结的架构精髓:SOLID原则,可以有效之道我们如何构建每一个程序模块。

S代表Single Responsibility Principle,即单一责任原则:每个模块都只有一个需要被改变的理由。据说与Conway Law直接相关。

O代表Open Close Principle,即开闭原则:允许新增代码来改变系统的行为,而不允许通过改变老代码来改变系统行为。Software entities (classes, modules, functions) should be open for extension but closed for modification

L代表Liskov Substitution Principle,李氏替换原则:组件之间必须满足设计约束才可以相互替换;派生类(子类)对象可以在程序中代替其基类(超类)对象。

I代表Interface Segregation Principle,接口隔离原则:客户(client)不应被迫使用对其而言无用的方法或功能。Clients should not be forced to depend upon interfaces that they don't use。接口隔离,避免不必要的依赖。

D代表Dependency Inversion Principle,依赖反转原则:高层次的策略性代码不应该依赖于底层的实现性代码,依赖关系应该反过来。例如业务逻辑不应该依赖UI或者数据库。High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions。

作者继续阐明组件构建原则。

组件定义:组件是程序部署的最小单元,即可执行文件和库,比如jar文件。

组件的聚合要满足以下三个原则:

  1. REP 复用/发布等同原则:软件复用的最小粒度应该等同与发布的最小粒度。这样任何变更不会导致过多的发布,或者过度的源代码修改。
  2. CCP 共同闭包原则:把那些会同时修改,并且为相同目的而修改的软件模块(类)放到同一个组件中去,即共同闭包。这实际是SRP在组件级别的重述,因为可维护性的重要性远大于可复用性。我们可以通过组件张力图,去计量共同闭包。
  3. CRP 共同复用原则:不要强迫一个组件的用户依赖他们不需要的东西。

组件的耦合应该满足下面三个原则:

  1. 无循环依赖原则:组件依赖关系中不应该出现环状结构。如果有,可以通过DIP解决。
  2. 稳定依赖原则:依赖关系必须指向更稳定的方向。被依赖的最多的组件应该是最稳定的,因为它难以被修改。计量关系:I = Fan-out/(Fan-in + Fan-out)。接口最稳定。
  3. 稳定抽象原则:一个组件的抽象化程度应该与其稳定性保持一致。

讲完组件,作者开始阐述软件架构。

主要是把策略和细节分离,在整个软件中,合理的划分边界,同时合理的规划好边界之间的依赖关系。同时做好策略与层次的设计:低层次的组件应该去依赖高层次的组件。

业务逻辑作为程序中最核心的用来挣钱/省钱的逻辑,应该位于层次同心圆最中间。而实现细节,或者I/O(UI、数据库等),则应位于最外面。依赖关系则是,最外面依赖最里面。

个人感觉,软件架构计时做好合理的分层,这里包括水平和垂直分层两个部分。水平只的是从UI、业务逻辑、持久化等数据流去分层;垂直分层则是从业务模块和领域的角度去分层,例如订单模块、CRM模块等。一个合理的软件架构,应该同时考虑这两种分层,并选择与之相应较好的侧重点。Salesforce是典型的侧重水平分层的平台,有明确的UI层(Visualforce Page、aura、lwc)、逻辑层(Apex)、数据层(SOQL、DML)。而目前流行的微服务架构,则更侧重垂直分层。

这两种分层的取舍,作者并没有过多解释,只是强调了策略与细节、分层与边界、分层与依赖等更加基础的内容。为什么?我猜是因为在架构上去侧重某种分层,结果就是出现框接,而作者认为框架是细节,并非架构。

作者还强调很多看起来像框架的东西,其实是实现细节

比如数据库、Web、应用程序框架,他们都是实现细节。

作者还对一个视频销售网站的架构设计,进行了精彩的讨论。

在另外一个人写的拾遗部分,主要讨论了作者的理论和自己的理解。

最后,作者回顾了从20世纪60年代到90年代,作者的软件工作生涯。可以从中看到作者不断总结教训经验,慢慢得出本书的这套理论。

参考

  1. douban 架构整洁之道
  2. wiki 开闭原则
  3. wiki 里氏替换原则
  4. wiki 接口隔离原则
  5. wiki SOLID
  6. zhihu 小话设计模式原则之:依赖倒置原则DIP