3、系统架构文档:架构图绘制规范
系统架构文档,说白了就是给整个项目画一张「地图」。
我见过太多团队,代码写得飞起,但问起系统长什么样,每个人脑子里都有一幅不同的画。结果呢?联调时才发现接口对不上,部署时发现模块依赖乱成一锅粥。
所以,架构图不是画给领导看的摆设。它是团队沟通的通用语言。今天我就把我在多个项目中沉淀下来的绘制规范,掰开揉碎了讲给你听。
3.1 上下文图(Context Diagram)
上下文图是架构文档的第一张图。它的作用只有一个:划定系统边界。
你想想看,一个系统再复杂,它也是跟外部世界打交道的。谁在用你的系统?你的系统依赖了哪些外部服务?这些就是上下文图要回答的问题。
核心要素:
- 系统本身:用一个矩形框表示,框内写系统名称
- 外部用户:用小人图标或角色名表示,比如「终端用户」、「管理员」
- 外部系统:用矩形框表示,比如「支付网关」、「短信平台」
- 交互关系:用带箭头的连线表示,箭头上标注数据流或协议
我个人习惯,上下文图只用一张图,不要超过 10 个外部实体。如果超过,说明你的系统边界没划清楚。
我的经验:
有一次我在项目中画上下文图,发现系统居然直接依赖了三个不同的数据库。后来一查,有两个是历史遗留的,根本不需要。你看,一张图就能暴露问题。
3.2 容器图(Container Diagram)
上下文图之后,我们放大一步,看系统内部。容器图展示的是系统由哪些「容器」组成。
这里的「容器」不是 Docker 容器,而是指:Web 应用、移动 App、数据库、消息队列、微服务等独立部署的单元。
| 容器类型 | 图例样式 | 示例 |
|---|---|---|
| Web 应用 | 矩形 + 浏览器图标 | 前端 SPA、管理后台 |
| 后端服务 | 矩形 + 齿轮图标 | 用户服务、订单服务 |
| 数据库 | 圆柱体 | MySQL、Redis |
| 消息队列 | 矩形 + 队列图标 | Kafka、RabbitMQ |
画容器图时,我建议你注意三点:
- 每个容器都要标注技术栈,比如「Java Spring Boot」、「Node.js Express」
- 容器之间的通信协议要写清楚,是 HTTP/REST 还是 gRPC,还是异步消息
- 不要画得太细,容器图只到「部署单元」级别,再细就是组件图的事了
避坑指南:
我曾经见过有人把容器图画成了部署架构图,连 IP 地址和端口号都标上去了。没必要。容器图关注的是逻辑关系,不是物理部署。
3.3 组件图(Component Diagram)
组件图是架构图的最后一层。它把一个容器拆开,展示内部有哪些组件,以及组件之间的调用关系。
举个例子,「用户服务」这个容器内部,可能有这些组件:
- Controller:接收 HTTP 请求
- Service:处理业务逻辑
- Repository:访问数据库
- Client:调用外部服务
画组件图时,我有个习惯:每个组件只写它的核心职责,不要写方法名。比如「用户注册」、「密码校验」这种,而不是「registerUser()」、「checkPassword()」。
组件图的关键信息:
- 组件名称
- 组件职责(一句话)
- 组件之间的依赖关系(箭头方向从调用方指向被调用方)
- 组件使用的关键技术(如 Spring Data JPA、Redis Client)
3.4 接口定义表
光有图还不够。图是给人看的,接口定义是给机器和代码看的。
接口定义表要包含以下字段:
| 字段 | 说明 | 示例 |
|---|---|---|
| 接口名称 | 简短描述接口功能 | 用户注册 |
| 请求方法 | GET / POST / PUT / DELETE | POST |
| 请求路径 | 完整的 URL 路径 | /api/v1/users/register |
| 请求参数 | 参数名、类型、是否必填 | username(string, 必填), password(string, 必填) |
| 响应格式 | 成功和失败的响应结构 | { "code": 0, "data": { "userId": 123 } } |
| 错误码 | 可能返回的错误码及含义 | 1001: 用户名已存在 |
我的建议:
接口定义表最好跟代码中的 API 文档自动同步。我习惯用 Swagger/OpenAPI 规范,然后从代码生成文档。这样接口改了,文档不会忘更新。
3.5 技术选型说明
技术选型说明,是架构文档里最容易被人忽略,但最体现功底的部分。
很多人写技术选型,就列个表格:用了什么框架、什么数据库。完了。这不行。
你要写清楚:为什么选这个,不选那个。
举个例子:
- 数据库选了 PostgreSQL 而不是 MySQL,为什么?因为我们需要 JSONB 数据类型和地理空间查询
- 消息队列选了 RabbitMQ 而不是 Kafka,为什么?因为我们的业务场景是任务分发,不是日志流处理,RabbitMQ 的 ACK 机制更适合
- 前端框架选了 React 而不是 Vue,为什么?因为团队里大部分人熟悉 React,而且项目需要大量的状态管理
技术选型说明的模板:
## 技术选型:消息队列
### 选型结果
RabbitMQ 3.12.x
### 备选方案
- Apache Kafka 3.5.x
- Redis Stream
### 选型理由
1. 业务场景:任务分发,需要可靠的消息确认机制
2. 团队经验:团队有 RabbitMQ 的生产运维经验
3. 运维成本:已有 RabbitMQ 集群,无需额外部署
### 风险与应对
- 风险:RabbitMQ 吞吐量不如 Kafka
- 应对:当前业务峰值 2000 TPS,RabbitMQ 可支撑 1 万 TPS,预留 5 倍余量
避坑指南:
我曾经见过一个项目,技术选型写的是「因为 Redis 快,所以用 Redis 做消息队列」。结果业务量上来后,消息丢失、数据不一致,改都改不动。技术选型不是比谁快,而是比谁更适合。
嗯,到这里,系统架构文档的核心内容就讲完了。记住一句话:图是骨架,表是血肉,选型说明是灵魂。三者缺一不可。