作为一个程序员,假如让你绘制当前正在开发的项目的架构图,你会怎么绘制?
背景
先来同步一个理念。架构图的作用是什么?
我回答一下:
提供了一个简单的方法给到开发团队(从开发工程师,测试工程师,架构师,测试,项目经历,产品经理,交互设计师,用户)能够更简单的描述和沟通软件架构,让团队每个人脑子里的架构可视化,更容易理解,形成统一;
归纳一下: 画个图让团队更好好的理解软件架构,并统一认知;
下面,我简单思考一下作为程序员应该如何绘制当前正在开发项目的架构图。
问题 | 回答 |
---|---|
where are we?现状 | 我是程序员,不知道怎么绘制项目的架构图 |
where are we go?目的 | 可绘制方便平级,上级之间沟通交流的架构图 |
how can we go there?实现路径 | C4PlantUML |
实现路径
C4模型
一种架构设计的方法论,忽略不在同一个抽象成绩的细节,从而可以更好的表达和可视化。
可以类比地图,地图分4个级别,国家,省,市,街道;
而C4模型也分4个层级,Context系统上下文,Container容器,Component组件,Code代码;
加上3种补充视图,即系统全景图,动态图,部署图,即可完整的描述一个项目的软件架构;
布局
分4个
布局说明 | 语法 |
---|---|
从上到下 | LAYOUT_TOP_DOWN |
从左到右 | LAYOUT_RIGHT_LEFT |
自由布局 | LAYOUT_WITH_LEGEND |
素描布局 | LAYOUT_AS_SKETCH |
可自定义更多的布局,源码是基于plantUML语法;
Context上下文
元素如下:
元素名称 | 函数 |
---|---|
角色 | Person |
外部角色 | Person_Ext |
关注的软件系统 | System |
外部软件系统 | System_Ext |
系统数据库 | SystemDb |
系统外部数据库 | SystemDb_Ext |
系统虚框 | System_Boundry |
企业虚框 | Enterprise_Boundry |
可以使用plantUML绘制系统全景图,系统物理部署图;
下面是一个例子:
- @startuml "enterprise"
- !include ../C4_Context.puml
- LAYOUT_TOP_DOWN
- LAYOUT_WITH_LEGEND()
- Person(customer, "客户", "一种限制工具的客户")
- Enterprise_Boundary(c0, "限制工具") {
- Person(csa, "客户服务代理", "处理客户询问")
- System(ecommerce, "电子商务系统", "允许客户通过widgets.com站点在线购买工具")
- System(fulfilment, "履行系统", "负责处理和传递客户订单")
- }
- System(taxamo, "Taxamo", "计算本地税务并扮演Braintree支付前台")
- System(braintree, "Braintree支付", "处理信用卡支付购买工具")
- System(post, "泽西邮报", "计算全世界的包裹邮费")
- Rel_R(customer, csa, "咨询", "电话")
- Rel_R(customer, ecommerce, "下工具订单")
- Rel(csa, ecommerce, "查询订单信息")
- Rel_R(ecommerce, fulfilment, "发送订单信息")
- Rel_D(fulfilment, post, "获取物流费用")
- Rel_D(ecommerce, taxamo, "代理信用卡处理")
- Rel_L(taxamo, braintree, "使用信用卡")
- Lay_D(customer, braintree)
- @enduml
Container容器
元素如下:
元素名称 | 函数 |
---|---|
容器 | Container |
容器数据库 | ContainerDb |
容器虚框 | Container_Boundry |
- @startuml
- !include ../C4_Container.puml
- LAYOUT_TOP_DOWN
- LAYOUT_WITH_LEGEND()
- title 网银系统容器图
- Person(customer, 客户, "银行客户有自己的私人银行账号")
- System_Boundary(c1, "网银") {
- Container(web_app, "Web 应用", "Java, Spring MVC", "传递静态内容和网银SPA")
- Container(spa, "单页应用", "JavaScript, Angular", "通过浏览器对用户提供所有的网银功能")
- Container(mobile_app, "手机应用", "C#, Xamarin", "通过手机设备提供有限的网银功能")
- ContainerDb(database, "数据库", "SQL 数据库", "存储用户的注册信息,随机认证密码,访问日志等")
- Container(backend_api, "API应用", "Java, Docker容器", "通过API提供网银功能")
- }
- System_Ext(email_system, "邮件系统", "网络软件交换系统")
- System_Ext(banking_system, "Mainframe银行系统", "存储所有的核心客户,账号,事务银行信息")
- Rel(customer, web_app, "使用", "HTTPS")
- Rel(customer, spa, "使用", "HTTPS")
- Rel(customer, mobile_app, "使用")
- Rel_Neighbor(web_app, spa, "传输")
- Rel(spa, backend_api, "使用", "异步, JSON/HTTPS")
- Rel(mobile_app, backend_api, "使用", "异步, JSON/HTTPS")
- Rel_Back_Neighbor(database, backend_api, "读写", "同步, JDBC")
- Rel_Back(customer, email_system, "发送邮件到")
- Rel_Back(email_system, backend_api, "发送邮件", SMTP")
- Rel_Neighbor(backend_api, banking_system, "使用", "同步/异步, XML/HTTPS")
- @enduml
Component组件
元素如下:
元素名称 | 函数 |
---|---|
组件 | Component |
组件数据库 | ComponentDb |
- @startuml
- !include ../C4_Component.puml
- LAYOUT_WITH_LEGEND()
- title 网银系统组件图 - API应用
- Container(spa, "单页应用", "javascript 和 angular", "通过浏览器提供所有的网银系统功能给到用户.")
- Container(ma, "手机应用", "Xamarin", "通过手机设备提供有限的网银系统功能给用户.")
- ContainerDb(db, "数据库", "关系数据库 Schema", "存储用户的注册信息, 随机认证令牌, 访问日志等.")
- System_Ext(mbs, "Mainframe银行系统", "存储用户,账号,交易等所有的核心银行信息.")
- Container_Boundary(api, "API 应用") {
- Component(sign, "登录控制器", "MVC Rest 控制器", "允许用户登录到网银系统")
- Component(accounts, "账户汇总控制器", "MVC Rest 控制器", "提供用户汇总的银行账号")
- Component(security, "安全组件", "Spring Bean", "提供登录,修改密码等相关功能")
- Component(mbsfacade, "Mainframe 银行系统 Facade", "Spring Bean", "一个mainframe 银行系统 facade.")
- Rel(sign, security, "使用")
- Rel(accounts, mbsfacade, "使用")
- Rel(security, db, "读写", "JDBC")
- Rel(mbsfacade, mbs, "使用", "XML/HTTPS")
- }
- Rel(spa, sign, "使用", "JSON/HTTPS")
- Rel(spa, accounts, "使用", "JSON/HTTPS")
- Rel(ma, sign, "使用", "JSON/HTTPS")
- Rel(ma, accounts, "使用", "JSON/HTTPS")
- @enduml
Code代码
即通用的,元素如下:
元素名称 | 函数 |
---|---|
虚框 | Boundry |
从上到下关系 | Rel |
反向关系 | Rel_Back |
从上到下关系 | Rel_U |
从下到上关系 | Rel_D |
从左到右关系 | Rel_L |
从右到左关系 | Rel_R |
代码级别可使用PlantUML绘制时序图,流程图,类图描述具体接口或者功能的实现细节;
这块是PlantUML的基础知识了,不详细展开,自行查阅资料即可。
- @startuml
- actor 用户 as user
- participant 浏览器 as browser
- participant 前端 as front
- participant 登录服务 as loginServer
- database 数据库 as db
- user -> browser: 打开登录页面
- browser->front:加载资源,输入账号密码
- front->loginServer:ajax请求
- loginServer->db:按照账号查询,校验密码
- return: 返回结果
- @enduml
C4PlantUML
它是两个东西的合体,提供了一种简单的方法来描述和沟通软件架构。
plantuml被创造用来允许你绘制UML图,使用简单和人类容易阅读的文本描述,因为它没有阻止你绘制反常的图,它只是一个绘图工具而不是一个建模工具;
他是使用最多的文本绘图工具,被wiki,论坛,文本编辑器和IDE强烈支持,可以使用不同的编程语言或者文档来生成;
C4模型对软件架构来说是一个抽象第一的绘图方式。基于抽象,可以反映出软件架构师和开发者是如何思考和构建软件的。
少量的抽象和绘图类型是的C4模型很容易学习和使用;
C4代表着context,containers,components,code;这一系列水平层级的图,你可以使用它来从不同的尺度向不同的听众描述你的软件架构。
C4模型和plantUML 分工如下:
技术点 | 用途 |
---|---|
plantUML | 写简单的代码即可绘图 |
c4模型 | 一种对系统架构的抽象的方法论 |
C4PlantUML | 定义一种C4模型的绘图风格,使用PlantUML进行文本绘图 |
使用方式:
下载 C4PlantUML 选择你熟悉的IDE集成即可使用;
IDE | 使用方式 |
---|---|
vscode | 安装 PlantUML 和 PlantUML Preview 插件 , Jdk , graphviz |
vscode引入
.vscode/C4.code-snippets . |
| idea | 下载plantUML插件,安装好 graphviz
打开C4PlantUML文件即可 |
命名规则:
- context 上下文图
- container 容器图
- component 组件图
- sequence 时序图
- usecase 用例图
- class 类图
- activity 活动图
- state 状态图
- object 对象图
- deployment 部署图
- timing 定时图
绘图步骤:
1.创建模型图名,按照上面的命名规则, xxx_项目名称.puml;
2.引入相对路径下的 path/C4_Component.puml
3.使用内置的函数,绘图;
小结
如果看完之后你只能记住一句话:C4PlantUML提供了一个绘图方式让你轻松的描述和表达软件架构;