共计 10797 个字符,预计需要花费 27 分钟才能阅读完成。
作者:京东物流 覃玉杰
1. 前言
本文将给大家介绍一种简洁明了软件架构可视化模型——C4 模型,并手把手教大家如何应用 代码 绘制出精美的 C4 架构图。
浏览本文之后,读者画的架构图将会是这样的:
注:该图例仅作绘图示例应用,不确保其完整性、可行性。
2. C4 模型
2.1 C4 模型整体介绍
C4 是软件架构可视化的一种计划。架构可视化,指的是用图例的形式,把软件架构设计精确、清晰、好看地示意进去。架构可视化不是领导开发者如何进行架构设计,而是领导开发者将架构设计表达出来,产出简洁直观的架构图。
架构可视化的办法有很多,支流的有“4+1”视图模型、C4 模型。视图模型形容的是架构自身,架构确定之后,不论用什么模型去表白,实质上都应该是一样的,并没有优劣之分。
C4 模型是一种易于学习、对开发人员敌对的软件架构图示办法,C4 模型没有规定应用特定的图形、特定的建模语言来画图,因此使用者能够非常灵活地产出架构图。
C4 模型将零碎从上往下分为 System Context, Containers, Components, Code 四层视图,每一层都是对上一层的欠缺和开展,层层递进地对系统进行形容,如下图。
2.2 System Context diagram
System Context(零碎上下文)视图位于顶层,是软件系统架构图的终点,表白的是零碎的全貌。System Context 视图重点展现的是零碎边界、零碎相干的用户、其余撑持零碎以及与本零碎的交互。本层不波及到具体细节(例如技术选型、协定、部署计划和其余低级细节),因而 System Context 能够很好地向非技术人员介绍零碎。
作用:清晰地展现待构建的零碎、用户以及现有的 IT 基础设施。
范畴:待形容的外围零碎以及其相干用户、撑持零碎,不应该呈现与外围零碎无关的其余零碎。例如咱们要形容一个打车零碎,不应该把无关联的药店零碎绘制进去,并且要确保一个 System Context 只有一个待形容的软件系统。
次要元素:Context 内待形容的软件系统。
反对元素:在范畴内间接与次要元素中的软件系统有关联的人员(例如用户、参与者、角色或角色)和内部依赖零碎。通常,这些内部依赖零碎位于咱们本人的软件系统边界之外。
指标受众:软件开发团队内外的所有人,包含技术人员和非技术人员。
举荐给大多数团队:是的。
示例:
这是该网上银行零碎的零碎上下文图。它显示了应用它的人,以及与该零碎有关系的其余软件系统。网上银行零碎是将要建设的零碎,银行的集体客户应用网上银行零碎查看其银行账户的信息并进行领取。网上银行零碎自身应用银行现有的大型机银行零碎来执行此操作,并应用银行现有的电子邮件系统向客户发送电子邮件。
图例:
2.3 Container diagram
Container(容器)视图是对 System Context 的放大,是对 System Context 细节的补充。
留神这里的容器,指的不是 Docker 等容器中间件。Container 的形容范畴是一个可独自运行 / 可部署的单元。Container 个别指的是利用以及依赖的中间件,例如服务器端 Web 应用程序、单页应用程序、桌面应用程序、挪动应用程序、数据库架构、文件系统、Redis、ElasticSeach、MQ 等。
Container 显示了软件架构的高级形态以及零碎内各容器之间的职责分工。
在 Container 这一层,还显示了零碎的次要的技术选型以及容器间的通信和交互。
作用:展现零碎整体的开发边界,体现高层次的技术选型,裸露零碎内容器之间的分工交互。
范畴:单个软件系统,关注的零碎外部的利用形成。
次要元素:软件系统范畴内的容器,例如 Spring Boot 打包后的利用,MySQL 数据库、Redis、MQ 等。
反对元素:间接应用容器的人员和内部依赖零碎。
指标受众:软件开发团队内外的技术人员,包含软件架构师、开发人员和经营 / 反对人员。
举荐给大多数团队:是的。
留神:Container 视图没有阐明部署计划、集群、复制、故障转移等。部署相干的视图,会通过 Deployment 视图进行展现。
示例:
网上银行零碎(此时 System Contenxt 中的零碎曾经被开展,所以用虚线框示意)由五个容器组成:服务器端 Web 应用程序、单页应用程序、挪动应用程序、服务器端 API 应用程序和数据库。
- Web 应用程序是一个 Java/Spring MVC Web 应用程序,它只提供形成单页应用程序的动态内容(HTML、CSS 和 JS)。
- 单页应用程序是在客户的网络浏览器中运行的 Angular 应用程序,是网上银行性能的前端。
- 客户也能够应用跨平台 Xamarin 挪动应用程序来拜访网上银行。
- 单页应用程序和挪动应用程序都应用 JSON+HTTPS API,该 API 由运行在服务器上的另一个 Java/Spring MVC 应用程序提供。
- API 应用程序从关系数据库中获取用户信息。
- API 应用程序还应用专有的 XML/HTTPS 接口与现有的大型机银行零碎进行通信,以获取无关银行账户的信息或进行交易。
- 如果 API 应用程序须要向客户发送电子邮件,它也会应用现有的电子邮件系统。
该容器图的图例如下,次要是引入了数据库、APP、浏览器的图例。
2.4 Component diagram
将单个容器放大,则显示了该容器外部的组件。Component(组件)视图显示了一个容器是如何由许多“组件”组成的,每个组件是什么,它们的职责以及技术实现细节。
作用:展现了可执行的容器外部形成与分工,可间接领导开发。
范畴:单个容器。
次要元素:范畴内容器内的组件,通常能够是 Dubbo 接口、REST 接口、Service、Dao 等。
反对元素:间接连贯到容器的人员和内部依赖零碎。
指标受众:软件架构师和开发人员。
举荐给大多数团队:Component 用于领导开发,当有须要时创立。
示例:
图例:
2.5 Code diagram
放大组件视图,则失去出组件的 Code 视图(代码视图)。
Code 视图个别采纳 UML 类图、ER 图等。Code 视图是一个可选的具体级别,通常能够通过 IDE 等工具按需生成。除了最重要或最简单的组件外,不倡议将这种具体水平用于其余任何内容。
在重视麻利开发的明天,个别不倡议产出 Code 视图。
范畴:单个组件。
次要元素:范畴内组件内的代码元素(例如类、接口、对象、函数、数据库表等)。
指标受众:软件架构师和开发人员。
举荐给大多数团队:不,大多数 IDE 能够按需生成这种级别的详细信息。
2.6 System Landscape diagram
C4 模型提供了单个软件系统的动态视图,不论是 System Context、Container、Component 都是针对单个软件系统的进行形容的,但在理论中软件系统不会孤立存在。为形容所有这些软件系统如何在给定的企业、组织、部门等中与其余零碎组合在一起,C4 采纳扩大视图 System Landscape(零碎景观图)。
零碎景观图实际上只是一个没有特定关注的软件系统的零碎上下文图(System Context diagram),零碎景观图内的软件系统都能够采纳 C4 进行深入分析。
适用范围:企业 / 组织 / 部门 / 等。
次要元素:与所选范畴相干的人员和软件系统。
指标受众:软件开发团队内外的技术人员和非技术人员。
示例:
图例:
2.7 Dynamic diagram
Dynamic diagram(动态图)用于展现动态模型中的元素如何在运行时合作。动态图容许图表元素自在排列,并通过带有编号的箭头以批示执行程序。
范畴:特定性能、故事、用例等。
次要元素和反对元素:依照理论须要,能够是软件系统、容器或组件。
指标受众:软件开发团队内外的技术人员和非技术人员。
示例:
图例:
2.8 Deployment diagram
Deployment diagram(部署图)用于阐明动态模型中的软件系统(或容器)的实例在给定环境(例如生产、测试、预发、开发等)中的部署计划。
C4 的部署图基于 UML 部署图,但为了突出显示容器和部署节点之间的映射会做稍微的简化。
部署节点示意示意软件系统 / 容器实例运行的地位,相似于物理基础架构(例如物理服务器或设施)、虚拟化基础架构(例如 IaaS、PaaS、虚拟机)、容器化基础架构(例如 Docker 容器)、执行环境(例如数据库服务器、Java EE web/ 应用服务器、Microsoft IIS)等。部署节点能够嵌套,也能够将基础设施节点包含进去,例如 DNS 服务、负载平衡器、防火墙等。
能够在部署图中随便应用 Amazon Web Services、Azure 等提供的图标,只需确保被应用的任何图标都蕴含在图例中,不产生歧义。
范畴:单个部署环境中的一个或多个软件系统(例如生产、暂存、开发等)。
次要元素 :部署节点、软件系统实例和容器实例。
反对元素:用于部署软件系统的基础设施节点。
指标受众:软件开发团队内外的技术人员;包含软件架构师、开发人员、基础架构架构师和经营 / 反对人员。
示例:
网上银行零碎的开发环境部署图:
图例
网上银行的生产环境部署图:
图例
2.9 C4 模型标准以及 Review CheckList
为了确保 C4 模型的架构图的可读性,C4 模型提供了作图标准,并且提供了 CheckList 供自查。
2.9.1 C4 模型标准
- 图表
每个图都应该有一个形容图类型和范畴的题目(例如“我的软件系统的零碎环境图”)。
每个图表都应该有一个要害 / 图例来解释所应用的符号(例如形态、色彩、边框款式、线型、箭头等)。
首字母缩略词和缩写词(业务 / 畛域或技术)应为所有受众所了解,或在图表键 / 图例中进行解释。
- 元素
应明确指定每个元素的类型(例如,人员、软件系统、容器或组件)。
每个元素都应该有一个简短的形容,以提供要害职责的“高深莫测”的视图。
每个容器和组件都应该有明确指定的技术。
- 关系
每条线都应该代表一个单向关系。
每一行都应该被标记,标记与关系的方向和用意统一(例如依赖或数据流)。尝试尽可能具体地应用标签,最好防止应用“应用”等单个词。
容器之间的关系(通常代表过程间通信)应该有明确标记的技术 / 协定。
2.9.2 Review Checklist
C4 模型图表绘制实现后,能够通过 Review Checklist 进行自查,查看是否有不标准之处。Review Checklist 被制成网页,能够通过 https://c4model.com/review/ 进行拜访。
3. C4 模型架构图代码绘制实战
3.1 文本绘图工具选型
对于 C4 模型的架构图的绘制,个别有两种形式:
第一种是采纳绘图工具,这类工具间接拖拽元素、调整款式,即可产出图片,例如 draw.io、PPT 等工具。绘图工具的长处是非常灵活,能够满足很多细节需要;毛病是通常调整元素的款式会比拟繁琐。
第二种是采纳基于文本的绘图工具,依据肯定的语法去形容图片元素,最初依据文本主动渲染成图片,例如 PlantUML。基于文本的绘图工具的长处是绘图快捷,只有依据语法写出形容文件,即可渲染进去,元素的款式曾经默认调试好;毛病是款式不肯定合乎咱们的审美,调整不不便。
本文着重解说第二种,即基于文本的绘图工具。
基于文本的绘图工具有很多,例如:structurizr、PlantUML、mermaid,别离有本人的语法。
工具 | 语法 | 应用形式 | 地址 |
---|---|---|---|
structurizr | DSL | 提供 Web 界面渲染图片,并且能够生成 C4-PlantUML 和 mermaid 的代码 | https://structurizr.com/ |
C4-PlantUML | PlantUML | VS Code 插件、IntelliJ Idea 插件 | https://github.com/plantuml-stdlib/C4-PlantUML |
mermaid | mermaid | Markdown 插件,提供 Live Editor | https://mermaid.js.org/syntax/c4c.html ,Mermaid Live Editor |
因为 IntelliJ Idea、VS Code 目前在开发者中十分遍及,咱们抉择应用 C4-PlantUML,联合 VS Code 和 IntelliJ Idea 别离进行 C4 模型的绘制。
VS Code 环境的装置,见 3.2。
IntelliJ Idea 环境的装置,见 3.3
3.2 VS Code 下 C4-PlantUML 装置
3.2.1 装置 VS Code
间接官网下载安装即可,过程略去。
3.2.2 装置 PlantUML 插件
在 VS Code 的 Extensions 窗口中搜寻 PlantUML,装置 PlantUML 插件。
3.2.3 配置 VS Code 代码片段
装置完 PlantUML 之后,为了提高效率,咱们最好装置 PlantUML 相干的代码片段。
关上 VS Code 菜单,层级为 Code→Preferences→User Snippets,如下图:
在抉择 Snippets File Or Create Snippets 弹窗中,抉择 New Global Snippets file,如下图:
在接下来的弹窗中,输出 Snippets file 的文件名,如下图:
应用浏览器关上以下链接,并将浏览器返回的文本内容粘贴到 VS Code 编辑区
https://github.com/plantuml-stdlib/C4-PlantUML/blob/master/.vscode/C4.code-snippets
如图:
3.2.4 装置 Graphviz
如果图形渲染呈现问题,提醒装置 graphviz 库,间接到 graphviz 官网装置即可。官网链接如下:
https://graphviz.gitlab.io/download/
Mac 零碎举荐采纳 MacPorts 装置。
3.3 IntelliJ Idea 下 C4-PlantUML 装置
3.3.1 装置 Idea
3.3.2 装置 PlantUML Integration 插件
3.3.3 装置代码模版
通过以下链接,下载 IntelliJ live template。
https://github.com/plantuml-stdlib/C4-PlantUML/blob/master/intellij/c4\_live\_template.zip
通过菜单门路 File | Manage IDE Settings | Import Settings
,抉择下载的 ZIP 文件,c4_live_template.zip
,导入并重启 Idea 即可。
3.4 案例实战及 C4-PlantUML 语法介绍
C4-PlantUML 的具体语法能够到官网 github 我的项目主页(https://github.com/plantuml-stdlib/C4-PlantUML)去理解,在此只做简略介绍。
3.4.1 案例
以某招聘 APP 服务端架构图(Container 级)为例子进行解说,以下是渲染进去的效果图。
以下是残缺 plantuml 代码:
@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
!define SPRITESURL https://raw.githubusercontent.com/rabelenda/cicon-plantuml-sprites/master/sprites
!define DEVICONS https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons
!define DEVICONS2 https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons2
!define FONTAWESOME https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/font-awesome-5
!include DEVICONS/java.puml
!include DEVICONS/mysql.puml
!include DEVICONS2/spring.puml
!include DEVICONS2/redis.puml
!include DEVICONS2/android.puml
!include DEVICONS2/apple_original.puml
title 招聘 APP 架构图(Container)Person(P_User, "找工作的 APP 用户(应聘者)")
System_Boundary(Boundary_APP, "招聘 APP 零碎边界"){Container(C_ANDROID, "安卓挪动端", "android", "挪动 APP 安卓端",$sprite="android")
Container(C_IOS, "iOS 挪动端", "iOS", "挪动 APP iOS 端",$sprite="apple_original")
Container(C_GATEWAY, "HTTP 网关", "Netty", "鉴权、协定转换",$sprite="java")
Container(C_GATEWAY_CACHE, "网关缓存", "Redis", "缓存认证凭据",$sprite="redis")
Container(C_BFF, "BFF 网关", "Spring Boot","整合后端接口",$sprite="spring")
Container(C_CERT, "实名认证服务", "Spring Boot", "外部实名认证服务",$sprite="spring")
Container(C_BIZ_1, "职位服务", "Spring Boot", "公布、搜寻职位",$sprite="spring")
Container(C_PAYMENT, "领取服务", "Spring Boot", "外部领取服务",$sprite="spring")
ContainerDb(CDB_MYSQL, "职位信息数据库", "MySQL", "长久化职位信息",$sprite="mysql")
}
System_Ext(OUT_S_CERT, "实名认证服务","对用户进行姓名身份证号实名认证")
System_Ext(OUT_S_PAYMENT, "第三方领取服务","反对用户应用多种领取形式实现领取")
Rel(P_User, C_ANDROID, "注册登陆投递简历")
Rel(P_User, C_IOS, "注册登陆投递简历")
Rel(C_ANDROID, C_GATEWAY, "申请服务端","HTTPS")
Rel(C_IOS, C_GATEWAY, "申请服务端","HTTPS")
Rel_L(C_GATEWAY, C_GATEWAY_CACHE, "读写缓存","jedis")
Rel(C_GATEWAY, C_BFF, "将 HTTP 协定转为 RPC 协定","RPC")
Rel(C_GATEWAY, C_BIZ_1, "将 HTTP 协定转为 RPC 协定","RPC")
Rel(C_GATEWAY, C_PAYMENT, "将 HTTP 协定转为 RPC 协定","RPC")
Rel(C_BFF, C_CERT, "通过 BFF 解决之后,对外裸露接口服务","RPC")
Rel(C_BIZ_1, CDB_MYSQL, "读写数据","JDBC")
Rel(C_CERT, OUT_S_CERT, "对接内部查问实名信息接口","HTTPS")
Rel(C_PAYMENT, OUT_S_PAYMENT, "对接内部领取零碎","HTTPS")
left to right direction
SHOW_LEGEND()
@enduml
3.4.2 PlantUML 文件
PlantUML 文件以 puml 作为文件扩展名。
3.4.3 @startuml 和 @enduml
整个文档由 @startuml
和@enduml
包裹,是固定语法。
@startuml
@enduml
3.4.4 正文
PlantUML 中应用单引号(即'
)作为正文标识。
3.4.5 include 语句
首先是 C4 各个视图的 include 语句,以下语句代表引入了 C4 的 Context、Container、Component 视图。
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
其次是图标库:
!define SPRITESURL https://raw.githubusercontent.com/rabelenda/cicon-plantuml-sprites/master/sprites
!define DEVICONS https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons
!define DEVICONS2 https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons2
!define FONTAWESOME https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/font-awesome-5
!include DEVICONS/java.puml
!include DEVICONS/mysql.puml
!include DEVICONS2/spring.puml
!include DEVICONS2/redis.puml
!include DEVICONS2/android.puml
!include DEVICONS2/apple_original.puml
留神这里有一个 define 语法,先通过 !define 定义一个标识,之后应用该标识的中央都会被替换
!define DEVICONS2 https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons2
!include DEVICONS2/spring.puml‘等价于 !include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons2/spring.puml
应用图标时,只须要在元素的申明语句中退出 $sprite="xxx"
即可。
ContainerDb(CDB_MYSQL, "职位信息数据库", "MySQL", "长久化职位信息",$sprite="mysql")
3.4.6 C4 模型动态元素
Person:零碎的用户,可能是人或者其余零碎
System:代表行将建设的零碎,通常渲染为蓝色方块。
System_Ext:代表已存在的零碎,通常渲染为灰色方块。
System\_Boundary:某零碎开展为容器时,则将 System 改为 System\_Boundary,代表零碎的边界,外部搁置容器元素,通常渲染为虚线框。
Container:待建设的容器,通常渲染为蓝色方块。
Container_Ext:已建设容器,通常渲染为灰色方块。
Container\_Boundary:某容器开展为组件之后,则将 Container 改为 Container\_Boundary,代表容器的边界,外部搁置组件元素,通常渲染为虚线框。
ContainerDb:待建设数据库,通常渲染为蓝色圆柱。
ContainerQueue:待建设音讯队列,通常渲染为程度搁置的蓝色圆柱。
Component:待建设组件,通常渲染为蓝色方块。
Component_Ext:已建设组件,通常渲染为灰色方块。
动态元素的语法为:
Container(alias, "label", "technology", "description")
alias:是图内元素的惟一 ID,其余中央能够通过 alias 进行援用,比方在 Rel
中援用
label:代表元素的显示名称
technology:代表元素采纳的核心技术,包含但不限于开发语言、框架、通信协议等
description:代表元素的简略形容
对于 System\_Boundary 和 Container\_Boundary,则只须要 alias 和 label,大括号内是该元素边界内的子元素。
Container_Boundary(alias, "label"){
}
3.4.7 C4 模型的关系元素
Rel 代表两个元素之间的关系,其语法为:
Rel(from_alias, to_alias, "label", "technology")
from\_alias 是终点元素的别名,to\_alias 是起点元素的别名,label 则用来阐明这个关联关系,technology 代表采纳的技术、通信协议。例如:
Rel(C_IOS, C_GATEWAY, "申请服务端","HTTPS")
代表 iOS 客户端通过申请网关接口拜访服务端资源,采纳 HTTPS 的通信形式。
倡议在绘制 Rel
时标注出technology
。
3.4.8 C4-PlantUML 布局
C4-PlantUML 提供了多种主动布局计划,咱们能够依据理论须要进行抉择。
- LAYOUT\_TOP\_DOWN():从上往下布局,默认采纳该布局。如下图:
- LAYOUT\_LEFT\_RIGHT():从左到右,即横向搁置元素。
left to right direction
是 PlantUML 的语法,也能够间接用。
3.4.9 图例
通过 SHOW_LEGEND()
增加图例。