使用PlantUML绘制C4模型风格的软件架构图

1 C4模型回顾

最简概括4个C:

  • Context Diagram:背景图,系统如何融入环境(包括用户和其他系统)
  • Container Diagram:容器图,系统如何由容器(不是容器技术,应用程序 or 存储)组成
  • Compoment Diagram:组件图,展示特定容器的实现
  • Code Diagram:代码图,使用UML展示

上述4个C从上到下是逐步放大的,一般常画的是前2个。

更详细的,建议反复阅读官方原文

2 安装工具

  • VSCode
  • 插件:plantUML
  • 库:Graphviz

3 配置C4-PlantUML

使用国内镜像

git clone https://github.com/plantuml-stdlib/C4-PlantUML.git

下载后,需要做一些修改,针对根目录下*.puml:

将远程引用修改问本地引用:

' convert it with additional command line argument -DRELATIVE_INCLUDE="." to use locally
'!if %variable_exists("RELATIVE_INCLUDE")
'  !include %get_variable_value("RELATIVE_INCLUDE")/C4.puml
'!else
'  !include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4.puml
'!endif
!include ./C4.puml

诚然,上述修改过程非常蛋疼,我会在本文末尾给出另一种解决方案

4 绘制Context图

Context图反应了新建设系统与用户、其他系统的交互关系,代码如下:

@startuml
!include /Users/coder4/code/C4-PlantUML/C4_Context.puml

Person(user, "用户", "小程序电商系统的潜在用户")

AddElementTag("existing_system", $bgColor="#777", $borderColor="#555", $fontColor="white")

System_Boundary(c1, "小程序电商系统") {
    System(weappMallSystem, "小程序商城", "提供 浏览商品,添加购物车,下单,支付,联系客服,查询物流 等功能")
    System(ecomMiddlePlatform, "电商中台", "提供 商品中台 库存中台 物流中台 订单中台 等中台能力", $tags="existing_system")
}

System_Ext(weixinPlatform, "微信公众平台", "提供 用户授权、支付、推送 等功能")

Rel_D(user, weappMallSystem, "使用")
Rel_U(weixinPlatform, user, "交互")
Rel(weappMallSystem, ecomMiddlePlatform, "交互")
Rel(ecomMiddlePlatform, weixinPlatform, "交互")
Rel(weappMallSystem, weixinPlatform, "交互")

SHOW_FLOATING_LEGEND()

@enduml

解释一下:

  • 我们用绝对路径引入了C4-PlantUML,是的,这非常蛋疼,请看文末结尾给的替代方案
  • Person是用户,System是系统,System_Ext是外部系统
  • Rel是关系,可以附加方向,例如Rel_D希望关系在下部,可选值UDLR
  • System_Boundary是系统边界
  • AddElementTag自定义了查询边界,这主要是解决没有已存在系统这个组件的问题
  • SHOW_FLOATING_LEGEND在合适位置展示图例,如果不加这个,图例会展示在每一个元素上

整体渲染图如下:

 

 

 

 

 

 

 

5 绘制Container图

Container图是对Context图中,欲建设系统的放大,展示了其中每一个Container(客户端 or 服务 or 存储 or 消息队列)

代码如下:

@startuml
!include /Users/coder4/code/C4-PlantUML/C4_Container.puml
!define DEVICONS /Users/coder4/code/plantuml-icon-font-sprites/devicons
!include DEVICONS/java.puml
!include DEVICONS/mysql.puml
!include DEVICONS/webplatform.puml

!define FA5 /Users/coder4/code/plantuml-icon-font-sprites/font-awesome-5
!include FA5/weixin.puml

Person(user, "用户", "小程序电商系统的潜在用户")

System_Boundary(c1, "小程序电商系统") {
    Container(miniApp, "微信小程序", "mini", "用户交互的小程序前端", $sprite="weixin")
    Container(mallService, "商城微服务", "Java, Spring Cloud, Tomcat", "商品浏览、详情的业务逻辑", $sprite="java")
    Container(orderService, "订单微服务", "Java, Spring Cloud, Tomcat", "下单、订单的业务逻辑", $sprite="java")
    Container(miniService, "小程序微服务", "Java, Spring Cloud, Tomcat", "微信授权、推送等业务逻辑", $sprite="java")
    ContainerDb(database, "Database", "MySQL", "RDBMS数据库", $sprite="mysql")
}

System_Ext(ecomMiddlePlatform, "电商中台", "提供 商品中台 库存中台 物流中台 订单中台 等中台能力")

System_Ext(weixinPlatform, "微信公众平台", "提供 用户授权、支付、推送 等功能")

Rel_R(user, miniApp, "使用")
Rel(miniApp, mallService, "调用", "https")
Rel(miniApp, orderService, "调用", "https")
Rel(miniApp, miniService, "调用", "https")
Rel(orderService, miniService, "调用", "rpc")
Rel(mallService, miniService, "调用", "rpc")

Rel_L(miniService, weixinPlatform, "交互", "https")
Rel_U(weixinPlatform, user, "交互")
Rel_R(orderService, ecomMiddlePlatform, "调用", "rpc")
Rel_R(mallService, ecomMiddlePlatform, "调用", "rpc")

Rel(mallService, database, "读/写")
Rel(orderService, database, "读/写")
Rel(miniService, database, "读/写")

SHOW_FLOATING_LEGEND()


@enduml

 

解释一下:

  • 使用了绝对定位,不废话了,看文末解决方案
  • 引入了FontAwaresome for PlantUML,这里主要是java、mysql和weixin
  • Container每一个容器,这里要写名称、技术栈、用途

最终图如下:

 

 

 

 

 

 

6 国内的 C4-PlantUML / plantuml-icon-font-sprites 镜像

如果你仔细阅读github的例子,会发现原始例子都是直接引用https://githubcontent的,但是众所周知的原因,国内没发用。

实际上,我们只需在国内有一份https的拷贝,并且对原始代码(中的依赖)稍做替换,即可实现。

我在gitee建了两个镜像:

具体用法可以点进去看下,记得Star 🙂

Leave a Reply

Your email address will not be published.