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

相关推荐
早睡早起不秃头&3 小时前
【架构】- 从百工屋到多座房子:一则寓言读懂单体应用、模块化单体与微服务
系统架构
爱学习的程序媛18 小时前
2. 智能应用开发技术栈清单
ai·架构·系统架构·ai应用·智能体开发·智能应用开发
Shulex19 小时前
面向转化率优化的独立站实时客服系统架构与数据流实现
系统架构
码流子19 小时前
AI稽核精灵-Agent落地
大数据·人工智能·物联网·算法·系统架构
AFinalStone1 天前
Android7 多用户源码解析(五)应用安装与管理隔离机制
系统架构·aosp·多用户
AFinalStone1 天前
Android7 多用户源码解析(二)核心数据结构深度剖析
系统架构·aosp·多用户
沫璃染墨1 天前
《从零入门Linux系统篇(五十一):线程篇·四——pthread线程库详解:从线程创建到终止与分离》
linux·运维·服务器·开发语言·c++·系统架构·线程
带金箍的至尊宝1 天前
系统架构设计师笔记 03:CPU 结构、Cache 与总线怎么考
笔记·系统架构
新鲜势力呀1 天前
PHP 实战:用户登录频繁失败怎么办?从安全防护到登录系统架构优化完整方案
安全·系统架构·php