基于C4模型的架构图画法

Overview

前言

我们实现一个软件系统时,通常要提前想清楚这个系统包含哪些元素,这些元素之间的关系是怎样的;系统做完之后,我们也需要向团队其他成员讲解这个系统是如何构建的,这些过程里,都涉及到与人沟通。

如何把这个事情快速的讲清楚且让人印象深刻?单纯通过文字描述,虽能达成目标,但效率可能并没有图片高,这是由大脑处理文字的方式决定的:大脑在接受到文本输入后,先从记忆库搜索、联想,把文字转换成图片,然后根据经验进行演绎、归纳、理解。所谓一图胜千言,原因大约在此。通过图片来对系统中的实体以及实体之间的关系进行抽象描述,即软件架构图。早在软件出现之前,架构图这个概念就被各行各业广泛使用,例如装修行业,架构图用来描述房屋结构、水电布局、木工布局、灯具布局等。计算机出现后,这个词就沿用到了软件行业。

同一个软件系统,涉及不同的人参与,有不同的观察维度,画出的架构图也就有不同的形态。针对同一个形态的架构图,不同的人画法也不一样。那么问题来了,怎么去画这个架构图呢?有没有一个大家都认同的比较好的方式?

软件架构师西蒙布朗(写过《Software Architecture for Developers》)提出了C4模型,C4代指4个C,由以下几个单词的首字母组成:Context、Container、Component、Code。每个词代表一种类型的图,分别描述软件系统在不同缩放级别下的架构,就像下面的google地图,不同的缩放级别,看到的东西不一样,能讲的故事也不一样:

img

第一张图呈现的是地图中的一条路,指示从哪个方向走,详细而具体

第二张图在第一张图的基础上,缩小了几个级别,观察者能了解到这条路在一个岛中的具体位置及周围的海域信息

第三张图在第二张图的基础上,又缩小了几个级别,观察者能了解到这个岛与周围岛屿的位置关系

第四张图在第三张图的基础上,进一步缩小了几个级别,观察者能了解到更大的世界,感知更多的环境信息

C4模型介绍

img

类似于地图的放大与缩小,软件系统也可以用此种方式来观察。C4模型把软件系统从上而下、从整体到局部的方式呈现,使得团队成员能够快速了解系统构成。C4模型包含四个基本元素:system Context、Container、Component、Code.除此之外,需额外考虑使用这个系统的人(People)。接下来以一个互联网银行业务系统为例,详细介绍下这四种类型的图定义及具体画法。

System Context

系统上下文,软件运行的上下游环境,包含软件系统本身(software system)、使用本系统的人(people)、与此系统有交互(relation)的其他系统。这一层提供最高层次的抽象视图,不关注具体技术实现细节。通过此图,观察者能了解到大概的业务上下游及参与此业务的相关方,对系统有一个基本的定位。下图为互联网银行业务系统的系统上下文图例:中心位置为银行业务系统,个人储蓄客户通过此系统来查看余额、使用支付的功能;银行业务系统通过外部已经存在的邮件系统发送信息给客户;银行业务系统通过大型机银行业务系统维护客户、账单信息:

img

Container

容器,可以理解为一个软件进程,这个进程运行需要依赖代码和数据。将系统上下文放大看,software system 包含多个container,container之间存在依赖关系。下图为银行系统放大后的容器视图:

img

涉及的容器有基于浏览器实现的js单页面应用、css/js等静态资源Web服务、手机app、提供数据服务的API应用、提供数据存储的数据库。

通过容器视图,观察者能看清系统由哪些关键服务支持、哪些关键技术构建、容器之间以什么协议进行通信。在做技术保障时,团队成员能基于此图做技术决策。对于新加入团队的开发者,通过此图能快速知道在哪里添加代码。常见的容器有:

  • Server-side web application: 常见的如tomcat、nginx等提供http协议的应用
  • Client-side web application:WEB浏览器应用,通常有js框架如VUE编写
  • Client-side desktop application:桌面应用程序
  • Mobile app:手机端应用程序
  • Server-side console application:服务端控制台程序,没有界面
  • Microservice:微服务
  • Database:数据库
  • Cache cluster:缓存集群

容器符号画法如下图,主要包含名字、容器所用技术和功能描述:

img

容器之间通过线条来表达交互关系,画法如下图:

img

Component

组件,模块化的代码集合。将容器放大看,容器包含多个组件,组件之间存在调用关系。同一业务同一层次的代码,封装在一个组件里。通过组件视图,我们能了解到一个业务大致包含哪些关键功能以及这些功能的依赖关系。在实践过程中,组件设计要尽量满足分层原则,下层组件不能调用上层组件。组件内实现高内聚、组件间实现低耦合的原则。下图为银行系统组件视图:

img

组件这一层由于画的太过详细,当一个系统发展演变了几年后,通常会包含非常多的组件,且组件之间关系非常复杂,这种情况下想继续保持组件视图关联至最新的代码版本就比较困难了。C4模型作者的推荐方式将每个或者每几个组件单独画一张图,每一张图都有明确的表达目的,而一张巨型的组件图通常没什么实际意义、也不会有人有兴趣去详细看。

Code

代码,具体的业务实现代码,在面向对象的语言里就是具体的类、接口设计。将组件放大看,一个组件包含多段代码或者多个类、接口。在面向对象的语言中,这一层的视图描述的是类本身以及类之间的继承、组合、关联关系。图例可以用UML类图、实体关系图表示,有的IDE也能生成。这一层不推荐把所有的类、接口都画上,只要挑选最重要或者逻辑最复杂的几个,以帮助阅读者快速理解代码。

img

以上就是C4模型对软件系统不同抽象级别的展示。

完美架构图的要求

怎样的一张图是完美的?这个问题其实可以换个问法,什么样的沟通算是高效的?恋人之间有的时候不需要言语,一个表情就能心领神会。同样对于一张饱含诚意的软件系统架构图,不需要讲解,自描述就能让阅读者自己看懂。那么自描述要求包含哪些东西呢?

  • 图需要包含标题和类型,例如这是一张是容器视图还是组件视图
  • 图中所有形状、线条、箭头都需要有幕后说明,如正方形圆形分别代表什么、虚线实线分别代表什么,箭头指向代表什么
  • 每条线应该只有单向关系
  • 如果同一个元素有多种颜色表示,那么不同颜色分别代表什么含义需要有说明
  • 专业术语有必要时提供下说明

C4模型作者也提供了一个checklist:https://c4model.com/assets/software-architecture-diagram-review-checklist.pdf

基于C4模型实践,来张当前所负责的考拉直播业务系统上下文图:

img

参考

本文图片均来自C4模型官网https://c4model.com/ C4模型在线画图工具:https://structurizr.com 其他参考:https://www.infoq.com/articles/crafting-architectural-diagrams/