花了一个多月读完了这本《架构整洁之道》,跟《代码整洁之道》《程序员的职业素养》算是一个 Clean 系列,每一本读来都很有启发。这本《架构整洁之道》有些地方看得还挺迷糊,值得一读再读。

概述、编程范式

设计与架构没有任何区别。一丁点区别都没有!软件架构的终极目标是,用最小的人力成本来满足构建和维护该系统的需求。

三种编程范式(结构化编程、面向对象编程和函数式编程)与软件架构的三大关注重点不谋而合:功能性、组件独立性以及数据管理。

面向对象编程到底是什么?对一个软件架构师来说,其含义应该是非常明确的:面向对象编程就是以多态为手段来对源代码中的依赖关系进行控制的能力,这种能力让软件架构师可以构建出某种插件式架构,让高层策略性组件与底层实现性组件相分离,底层组件可以被编译成插件,实现独立于高层组件的开发和部署。

软件架构师应该着力于将大部分处理逻辑都归于不可变组件中,可变状态组件的逻辑应该越少越好。

设计原则

  • SRP: 单一职责原则。任何一个软件模块都应该只对某一类行为者负责。
  • OCP: 开闭原则。一个设计良好的软件系统应该在不需要修改的前提下就可以轻易被扩展。
  • LSP: 里氏替换原则。(没看明白,开头的定义和后面紧跟着的 License 类的例子似乎是矛盾的,疑似翻译错误,https://www.zhihu.com/question/22839841)
  • ISP: 接口隔离原则。在一般情况下,任何层次的软件设计如果依赖于不需要的东西,都会是有害的。
  • DIP: 依赖反转原则
  • 应在代码中多使用抽象接口,尽量避免使用那些多变的具体实现类
  • 不要在具体实现类上创建衍生类
  • 不要覆盖(override)包含具体实现的函数
  • 应避免在代码中写入与任何具体实现相关的名字,或者是其他容易变动的事物的名字

组件构建原则

组件是软件的部署单元,是整个软件系统在部署过程中可以独立完成部署的最小实体。

与构建组件相关的三个基本原则

  • REP:复用/发布等同原则
    软件复用的最小粒度应等同于其发布的最小粒度。
  • CCP:共同闭包原则
    我们应该将那些会同时修改,并且为相同目的而修改的类放到同一个组件中,而将不会同时修改,并且不会为了相同目的而修改的那些类放到不同的组件中。
  • CRP:共同复用原则
    不要强迫一个组件的用户依赖他们不需要的东西。

三个原则之间彼此存在着竞争关系。软件架构师的任务就是要在着三个原则中间进行取舍。一个项目在组件结构设计上的重心是根据该项目的开发时间和成熟度不断变动的,我们对组件结构的安排主要与项目开发的进度和它被使用的方式有关,与项目本身功能的关系其实很小。

组件耦合相关的原则

  • 无依赖环原则。组件依赖关系图中不应该出现环。
  • 自上而下的原则。组件结构图必须随着软件系统的变化而变化和扩张,而不可能在系统构建的最初就被完美设计出来。
  • 稳定依赖原则。依赖关系必须要指向更稳定的方向。
  • 稳定抽象原则。一个组件的抽象化程度应该与其稳定性保持一致。如果一个组件想要成为稳定组件,那么它就应该由接口和抽象类组成,以便将来扩展。

软件架构

软件架构师自身需要是程序员,并且必须一直坚持做一线程序员。

在软件系统的所有方面中,维护所需的成本是最高的。

所有的软件系统都是一组策略语句的集合。软件架构设计的工作重点之一就是,将这些策略彼此分离,然后将他们按照变更的方式进行重新分组。其中变更原因、时间和层次相同的策略应该被分到同一个组件中。优秀的架构师会小心地将软件的高层策略与其底层实现隔离开,让高层策略与实现细节脱钩,使其策略部分完全不需要关心底层细节,当然也不会对这些细节有任何形式的依赖。另外,优秀的架构师所设计的策略应该允许系统尽可能地推迟与实现细节相关的决策,越晚做决策越好。

层次、边界

一个软件系统可以被解耦成若干个水平分层——UI界面、应用独有的业务逻辑、领域普适的业务逻辑、数据库等。而系统的用例是系统水平分层的一个个垂直切片。

软件架构设计本身就是一门划分边界的艺术。边界的作用是将软件分割成各种元素,以便约束边界两侧之间的依赖关系。系统的核心业务逻辑必须和其他组件隔离,保持独立,而这些其他组件要么是可以去掉的,要么是有多种实现的。

业务逻辑应该保持纯净,不要掺杂用户界面或者所使用的数据库相关的东西。在理想情况下,这部分代码业务逻辑的代码应该是整个系统的核心,其他底层概念的实现应该以插件形式接入系统种。业务逻辑应该是系统中最独立、复用性最高的代码

软件架构师必须仔细权衡成本,决定哪里需要设计架构边界,以及这些地方需要的是完整的边界,还是不完全的边界,还是可以忽略的边界。我们的目标是找到设置边界的优势超过其成本的拐点,那就是实现该边界的最佳时机。

整洁架构

按照现有的一些优秀架构(六边形架构、DCI 架构、BCE 架构)设计出来的系统,通常都具有以下特点:

  • 独立于框架
  • 可被测试
  • 独立于 UI
  • 独立于数据库
  • 独立于任何外部机构

以几个同心圆画出来的整洁架构示意图,从里到外,各层分别是

  • 业务实体(系统级业务逻辑)
  • 用例(应用级业务逻辑)
  • 控制器、展示器、网关(接口适配器)
  • Web、用户界面、数据库、设备、外部接口(框架与驱动程序)

实现细节

数据库并不是数据模型。数据库只是一款软件,是用来存取数据的工具。一个优秀的架构师是不会让实现细节污染整个系统架构的。数据本身很重要,但数据库系统仅仅是一个实现细节。

GUI 只是一个实现细节。而 Web 则是 GUI 的一种,所以也是一个实现细节。

框架并不等同于系统架构——尽管有些框架确实以此为目标。我们应该将框架作为架构最外圈的一个实现细节来使用,不要让它们进入内圈。不要让框架污染我们的核心代码,应该依据依赖关系原则,将它们当作核心代码的插件来管理。

相同的架构方式,可能有多种不同的代码组织方式,好的组织方式能够利用编译器来维护架构设计原则,而不依赖个人自律和编译过程之后的工具。