作者:京东物流覃玉杰

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被制成网页,能够经过 c4model.com/review/ 进行访问。

手把手教你用代码画架构图 | 京东云技术团队

3. C4模型架构图代码制作实战

3.1 文本绘图东西选型

关于C4模型的架构图的制作,一般有两种方法:

第一种是选用绘图东西,这类东西直接拖拽元素、调整款式,即可产出图片,例如draw.io、PPT等东西。绘图东西的长处是十分灵敏,能够满意很多细节需求;缺点是一般调整元素的款式会比较繁琐。

第二种是选用根据文本的绘图东西,根据一定的语法去描绘图片元素,最后根据文本主动烘托成图片,例如PlantUML。根据文本的绘图东西的长处是绘图快捷,只要根据语法写出描绘文件,即可烘托出来,元素的款式现已默认调试好;缺点是款式不一定符合咱们的审美,调整不方便。

本文侧重解说第二种,即根据文本的绘图东西。

根据文本的绘图东西有很多,例如:structurizr、PlantUML、mermaid,分别有自己的语法。

东西 语法 运用方法 地址
structurizr DSL 供给Web界面烘托图片,而且能够生成C4-PlantUML和mermaid的代码 structurizr.com/
C4-PlantUML PlantUML VS Code插件、IntelliJ Idea插件 github.com/plantuml-st…
mermaid mermaid Markdown插件,供给Live Editor mermaid.js.org/syntax/c4c.… ,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修改区

github.com/plantuml-st…

如图:

手把手教你用代码画架构图 | 京东云技术团队

3.2.4 装置Graphviz

假如图形烘托呈现问题,提示装置graphviz库,直接到graphviz官网装置即可。官网链接如下:

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。

github.com/plantuml-st…

经过菜单途径File | Manage IDE Settings | Import Settings,挑选下载的 ZIP文件,c4_live_template.zip,导入并重启Idea即可。

3.4 案例实战及C4-PlantUML语法介绍

C4-PlantUML的详细语法能够到官网github项目主页( github.com/plantuml-st… )去了解,在此只做简略介绍。

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架构图(ContainerPerson(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()增加图例。

手把手教你用代码画架构图 | 京东云技术团队