4+1 视图是现代软件开发中经常被使用到的架构蓝图。早在 1995,Phillip Krutchen 就在他的大作《The “4+1” View Model of Software Architecture》里提出了这一个概念。他通过类比建筑行业中的结构、管线、电气等等不同的架构视角,得出结论道:同样具有“架构”概念的软件行业,也是需要各种视图加以阐明设计意图的。
概述
4+1,顾名思义,就是为不同的利益相关者(stakeholders)准备 4
种不同的视角和 1
种场景来阐述架构的设计意图,以便减少认知和交流的成本。我们看一下所谓的四种视图:“逻辑视图”、“实现视图”、“物理视图”、“进程视图”。
上面这种白描图是最抽象的 4+1 呈现,具体到到每一张视图,我们还需要包含以下内容:
- 为系统定义组件、连接器、容器等概念
- 为每个视图使用适当的样式、类型和模式加强表现力
- 考虑每个视图中的约束条件
- 从全局思考每种视图之间的关系
当然,现实中你也不一定有那么多利益相关者需要汇报;系统也不见得复杂到要需要多种视角才能完全理清业务场景。开始阶段不要陷入过度设计中;保持视图“可编辑”,并随着解决方案的成熟逐步改进架构设计;要像维护代码一样维护视图。所以,实践中我们通常还是会用老古董 UML 来绘制这几种视图。
Logical View
OK,说完抽象的概念,我们进一步讲解着几种视图的具体要义。
逻辑视图是开发人员创建的软件元素,用于阐明系统是如何分解为特定的功能区域。在面向对象设计语言中,这个视图就是所谓的类图或是包图。我们会绘制接口、类、包等元素,以及它们之间的关系——继承、关联、依赖等等。现在不是流行 DDD(领域驱动设计)嘛?它的界限上下文其实也属于逻辑视图的范畴。
Boundary ContextImplementation View
实现视图是构件编译系统的输出。它主要由打包的模块和组件构成。那什么是这里的模块和组件呢?以 Java 世界为例:
- 模块就是 Jar 文件,是一个或几个开发人员实现的业务子模块
- 组件就是 War 文件或是可执行的 Jar 文件,是多个模块的组合
开发视图绘制的便是这些模块之间的依赖关系,以及组件和模块之间的组合关系;通常会使用系统 I/O 关系的模型图或子系统图来描述具体内容。
SubsystemProcess View
进程视图用于描述系统运行时的动态特征:每一个元素都是进程,进程间的关系代表着进程间的通讯。进程视图中的组件是构成系统运行时的真实可执行文件,如:
- 浏览器中可运行的 SPA 应用
- Linux 守护进程
- 数据库运行的 SQL 脚本
进程视图的目的是通过捕获进程间信息交换的流程(例如 REST API 调用、总线上的消息传递)以及这些进程间通信的顺序和时间,使我们能够更深入地思考系统的并发性、分布性、集成性和容错能力等性能指标。
Physical View
物理视图描述的是进程如何到映射到机器的,即软件组件在物理层面的拓扑关系。此视图中的元素由物理或虚拟的机器和进程组成;机器之间的关系代表网络。物理视图在 MUL 中被称为部署图。
我们现在可能更多地会使用云服务,早期的 UML 部署图已经不够生动了。所以,也不需要太过教条主义,绘制物理视图的关键点还是在于描绘出哪些节点托管了从 Process View 中显示的进程,以便帮助我们理解系统性能和网络容量。
AWS cloud serverScenario
除了上述四个视图外,我们再解释一下 4+1
中的 1
——场景;它负责把所有视图串联起来。每个场景都用于描述视图中的多个架构元素是如何协作。“场景”在 UML 中对应的是 use case ;此外,场景也可以用文本描述,就是所谓的 use story了。架构师通常使用场景来分析一个特定的视图,或描绘不同视图之间是如何互相作用的。最后的效果就是让 stakeholders 充分理解逻辑、进程、实现、物理组件是如何关联并促成结果的。
小结
4+1 视图是开发中解释应用程序架构的最佳实践,每一个视图都描述了架构的一个重要侧面,最后再通过场景把这些视图联系起来。
优秀的架构设计可以极大地降低软件开发和维护中的认知成本和交流成本。但讽刺的是, 4+1 视图在 95 年被提出后,绝大多数软件从业者都不会绘制这类视图。我分析可能的原因是:在我们这个时代里,“软件质量”并不是软件产品成功的关键,它的受益没有想象得那么大。分析到这一层,也许会很绝望;但是作为从业者,我们事实上很难去把控真正的“关键”,我们能做的是:让自己的工作不那么糟心而已。
人最可贵之处在于看透生活的本质后,依然热爱生活。 -- 罗曼罗兰
文章同步发布于an-Onion 的 Github。码字不易,欢迎点赞。
网友评论