【架构】-C4模型:把架构图画到合适的层级

架构-C4模型:把架构图画到合适的层级

很多架构图的问题,不是画得不够多,而是把不同层级的东西放在了一起。

用户、外部系统、服务、数据库、业务模块和具体类同时出现在一张图里。读者看完仍然不知道系统边界在哪里,也不知道箭头表示调用、依赖还是数据流。这样的图通常只能由作者自己解释,无法作为团队共同使用的文档。

C4 模型针对的就是这个问题。它把架构拆成四个观察层级,让读者从系统边界一路看到代码结构:

text 复制代码
Context  →  Container  →  Component  →  Code
系统边界    运行单元      业务模块      代码结构

C4 模型由 Simon Brown 提出。它不替你选择单体、微服务或某种数据库,只规定如何把这些设计表达清楚。

四个层级怎么区分

层级 要回答的问题 可以放什么
Context 系统服务谁,依赖谁? 用户、当前系统、外部系统
Container 系统由哪些运行单元组成? 应用、服务、数据库、消息队列
Component 某个运行单元内部如何分工? 控制器、业务服务、适配器
Code 关键模块由什么代码实现? 类、接口、继承和依赖

这里的 Container 不是 Docker 的同义词。一个桌面客户端、一个后端服务或一个数据库,都可以作为 C4 的 Container。

也不必四层全画。大多数项目画清 Context 和 Container 就够了;只有在某个服务复杂到需要专门讨论时,才继续画 Component。Code 图更适合解释一个关键设计,而不是展示整个项目的类目录。

用订单系统举例

Context:先说清楚系统边界

假设要介绍一个订单系统。Context 图只放客户、订单系统以及它依赖的外部系统:

这张图解决两个问题:谁在使用订单系统,订单系统和谁交互。支付平台和仓储系统在边界之外;数据库、接口类和业务模块不应该出现在这里。

Container:再说明系统由什么组成

展开订单系统后,可以看到 Web 前端、订单 API、订单数据库、消息队列和库存服务:

这里需要让读者看懂运行关系。例如,Web 前端通过 HTTP 调用订单 API,订单 API 写入订单数据库并发布消息,库存服务消费消息。只写"API → 队列"是不够的,至少要说明通信方向和用途。

Component 和 Code:复杂处再展开

如果订单 API 已经承担了太多职责,可以把它拆成几个组件:

text 复制代码
订单 API
├── 订单控制器:接收并校验请求
├── 创建订单服务:编排下单流程
├── 库存网关:访问库存服务
├── 支付协调器:处理支付调用
└── 订单仓储:读写订单数据

这时讨论的是模块职责,不是文件夹结构。只有在需要解释接口设计、依赖方向或关键类时,才继续画 Code 图。一个简单服务如果已经能在 Container 图中讲清楚,就应该停在这里。

怎样从零开始绘制

先决定这张图给谁看

读者决定细节:

  • 给产品、管理者或新成员介绍系统,画 Context;
  • 讨论系统拆分和技术依赖,画 Container;
  • 评审某个复杂服务,画 Component;
  • 讨论关键实现,画 Code。

不要试图用一张图满足所有人。一张图只解决一个主要问题,读者才知道应该关注什么。

先写出系统边界

用一句话回答:

这个系统负责什么,不负责什么?

把当前系统放在边界内,把用户、外部系统和基础设施放在边界外。边界没定下来就开始画服务和数据库,最后得到的往往只是依赖清单。

绘制 Context

在中心放当前系统,周围放直接使用它的用户和它主动依赖的外部对象。关系要写业务含义,例如"提交订单""发起支付""同步库存"。这一层不画数据库、类名和内部模块。

拆分 Container

从当前系统内部找出可以独立运行、部署,或承担明确职责的单元:前端、桌面客户端、后端服务、数据库、消息队列、设备适配服务等。

每个 Container 至少写清名称、职责和技术形态:

text 复制代码
名称:订单 API
职责:接收订单请求,协调支付、库存和持久化
技术:HTTP 服务

箭头也要写清楚。相比"订单 API → 支付平台","订单 API 通过 HTTPS 发起支付请求 → 支付平台"能减少很多误解。

按职责划分 Component

Component 不应只是代码目录的另一种画法。按职责拆分,确保每个组件都能用一句话说明自己的工作,并通过明确的接口与其他组件协作。

Code 只画关键部分

Code 图可以展示核心接口、重要依赖和需要评审的类。不要把整个项目的类全部导出;那会变成一张难以维护的代码地图,也无法突出设计重点。

画完后检查

  • 一张图是否只表达一个抽象层级?
  • 每个元素是否写了名称和职责?
  • 每条箭头是否有方向、用途或通信方式?
  • 是否混入了与当前问题无关的细节?
  • 图中的结构是否仍符合当前代码和部署状态?

如果图已经塞不下重点,不要继续缩小字体。把复杂部分拆到下一层,或者改用时序图、部署图或数据模型图。

C4 不负责什么

C4 用来说明"系统由什么组成"。下面这些问题应交给其他图:

  • 时序图:对象如何按时间交互;
  • 部署图:系统运行在哪些节点;
  • ER 图:数据实体如何关联;
  • 流程图:业务步骤如何推进。

把这些内容硬塞进 C4 图,只会让图重新变得难读。

结语

C4 的用处,是让信息出现在合适的层级。先把系统边界和外部关系说清楚,再说明运行单元;只有确实需要时,才深入模块和代码。架构图画到读者已经能做出判断的地方,就该停笔。

相关推荐
高旭的旭16 小时前
图解 Android 系统架构:从 App、Framework、HAL 到 Linux 驱动
android·linux·系统架构
solihawk18 小时前
架构系列之软件架构设计基本概念
系统架构
ABB自动化19 小时前
ABB 500CIM06 (1MRB150077R0111) | REB500 通信接口
大数据·分布式·系统架构·系统安全·模块测试·plc 控制器
youandyouyou20 小时前
局域网视频会议系统架构拆解与私有化部署实践
系统架构·音视频·网络通信
2601_9653842620 小时前
从系统架构与微环境视角,拆解“口臭”的底层成因
系统架构
各类产品分享1 天前
工业现场 AR 巡检系统架构设计与落地实践
系统架构·ar·ar巡检
我命由我123452 天前
软件工程概念 - 可插拔性
java·后端·学习·java-ee·系统架构·软件工程·学习方法
Vitaliy Kostrov(柯维远)2 天前
客户端如何检查直播流:从流内标记到停止播放
android·运维·服务器·驱动开发·网络安全·系统架构·cdn
黄俊懿3 天前
【架构师从入门到进阶】第六章:服务集群优化——第八节:线程数公式
java·服务器·数据库·分布式·性能优化·架构·系统架构
黄鹂鸟科技3 天前
软件定制开发设计要点:从需求梳理、原型确认到敏捷交付与持续维护
后端·物联网·系统架构