架构图不是为了把系统画得复杂,而是为了让不同角色对同一件事形成一致理解。产品经理关心业务边界,开发工程师关心模块职责和调用关系,测试工程师关心流程分支和异常路径,技术负责人关心演进方向、成本和风险。如果这些信息只靠口头描述,很容易出现理解偏差。
一张有用的架构图至少要解决四类问题:
| 问题 | 架构图要表达的内容 |
|---|---|
| 系统做什么 | 业务范围、功能边界、关键能力 |
| 系统由什么组成 | 应用、模块、服务、组件、平台能力 |
| 各部分如何协作 | 调用关系、依赖关系、数据流、状态变化 |
| 系统如何落地 | 部署节点、网络关系、中间件、第三方系统 |
架构图的使用对象通常包括三类:
- 项目内的业务、产品、开发、测试、运维等角色;
- 项目外的客户、评审人员、合作方;
- 技术负责人、管理者、跨团队协作方。
不同对象关注的信息粒度不同。给开发团队看的图可以细到组件和接口调用,给业务方看的图更应该突出业务链路和能力边界,给管理者看的图则要能说明系统整体结构、关键依赖和建设成本。
一张好的架构图要满足什么条件
好的架构图不是元素越多越好,也不是颜色越丰富越好。它的核心标准很简单:看图人能快速理解图要表达的观点,并且不会因为术语、边界或方向产生误解。
| 维度 | 判断标准 |
|---|---|
| 结构清晰 | 层次分明,主次关系明确,模块之间的关系容易识别 |
| 内容完整 | 标题、图例、边界、箭头含义、关键注解齐全 |
| 术语一致 | 同一个系统、模块、角色在不同位置使用同一个名字 |
| 粒度一致 | 同一层级不要混放“系统”“接口”“数据库表”这类不同粒度的元素 |
| 视觉统一 | 颜色、线条、形状、字体、间距保持一致 |
| 能自解释 | 即使没有额外讲解,也能看出图表达的主要结论 |
四个基础版式原则
架构图也是一种视觉表达,基础设计原则同样适用。
| 原则 | 在架构图里的用法 |
|---|---|
| 亲密性 | 相关模块靠近放置,不相关模块拉开距离 |
| 对齐 | 同层模块保持水平或垂直对齐,减少视觉噪音 |
| 对比 | 用颜色、线型、粗细区分核心链路、辅助链路、外部依赖 |
| 重复 | 同类元素使用同一种样式,例如所有数据库都用圆柱体,所有服务都用矩形 |
颜色不要随意堆叠。配色可以用色轮辅助判断:两色场景适合用互补色突出主次,三色场景可以用等距三色组,多模块场景则更适合使用同一色系的不同深浅。
图中的色轮可以帮助确定颜色之间的关系。架构图里通常只需要一个主色、一个强调色,再加少量中性色。颜色越多,越需要图例说明,否则看图人会把颜色误解成某种业务含义。
构图要给重点留空间
架构图里的空间分配也会影响理解。核心模块应该出现在视线容易停留的位置,边缘依赖、辅助能力、外部系统可以放在外围区域。
黄金分割和斐波那契数列可以作为构图参考,但不需要机械套用。更实用的做法是:主链路占据最醒目的区域,辅助信息围绕主链路展开,避免让核心流程被大量边角说明淹没。
画架构图的核心思路:分层、分模块、分功能
系统复杂度上来以后,直接把所有东西塞进一张图里,结果通常是看不清。架构图需要先抽象,再表达。抽象最常用的三个动作是:分层、分模块、分功能。
flowchart TB
A[业务目标] --> B[能力拆解]
B --> C[横向分层]
C --> D[纵向模块划分]
D --> E[功能点归纳]
E --> F[选择合适的图类型]
F --> G[输出架构图]
横向分层:按照职责深度拆开
分层是管理复杂性的基础手段。每一层只处理自己负责的问题,下层为上层提供能力支撑,上层组合下层能力完成业务目标。
常见的软件系统可以按下面的方式分层:
flowchart TB
U[用户 / 外部系统] --> A[接入层:网关、Web 前端、开放接口]
A --> B[应用层:业务编排、权限校验、流程控制]
B --> C[领域层:核心业务规则、领域模型]
C --> D[基础能力层:缓存、消息队列、搜索、文件服务]
D --> E[(数据层:关系型数据库、NoSQL、对象存储)]
这类分层图适合说明“系统整体由哪些层组成,每层负责什么”。它不适合塞入过细的接口字段、数据库表结构或代码类名。
纵向切分:按照业务域或模块拆开
分层解决的是上下关系,模块解决的是左右关系。在同一层里,系统往往还要按业务域继续拆分,比如用户、订单、支付、库存、营销、风控等。
模块切分要尽量满足两个目标:
- 高内聚:模块内部围绕同一类业务能力组织;
- 低耦合:模块之间通过清晰接口协作,不随意访问彼此内部数据。
flowchart LR
subgraph 应用层
User[用户中心]
Order[订单中心]
Pay[支付中心]
Stock[库存中心]
Risk[风控中心]
end
User --> Order
Order --> Pay
Order --> Stock
Pay --> Risk
横向分层和纵向模块可以组合使用。分层告诉看图人“能力从上到下如何支撑”,模块告诉看图人“同一层内部有哪些独立业务单元”。
功能抽象:只保留代表性能力
模块内部还会有很多功能点。架构图不应该把所有按钮、接口、页面都画出来,而是提炼出能代表模块职责的功能。
以订单中心为例,适合放进架构图的功能通常是:
- 创建订单;
- 订单确认;
- 订单取消;
- 支付回调处理;
- 履约状态同步;
- 售后入口。
不适合放进系统级架构图的内容包括字段校验规则、页面按钮文案、某个接口的参数列表。细节不是不能画,而是应该放到更合适的图里,例如接口时序图、状态图或流程图。
画图前的整理流程
动手画之前,先把信息整理出来。直接打开画图工具拖矩形,很容易越画越乱。
flowchart LR
A[列出元素] --> B[合并同类项]
B --> C[确定层级和边界]
C --> D[选择图类型]
D --> E[安排布局]
E --> F[补充图例和说明]
F --> G[找目标对象验证]
每一步要关注的内容如下:
| 步骤 | 要做什么 |
|---|---|
| 列出元素 | 把系统、服务、模块、数据库、中间件、外部系统、角色全部列出来 |
| 合并同类项 | 把粒度相近、职责相近的元素归类 |
| 确定边界 | 明确哪些属于当前系统,哪些是外部依赖 |
| 选择图类型 | 按表达目标选择组件图、部署图、时序图、状态图等 |
| 安排布局 | 主链路居中,支撑能力放下方或侧边,外部系统放边界之外 |
| 补充说明 | 标题、图例、箭头含义、颜色含义、关键约束不能缺失 |
| 验证理解 | 让目标对象只看图说出理解结果,发现歧义后调整 |
UML 七类常见图的使用方法
UML(统一建模语言)是一套用图形描述软件系统的建模语言。它的价值不在于记住所有符号,而在于用统一的表达方式描述系统结构、行为和约束。
常用的七类图可以按问题来选:
| 想回答的问题 | 适合使用的图 |
|---|---|
| 类、对象、数据模型之间有什么静态关系 | 类图 |
| 一次请求或业务动作如何在多个对象之间传递 | 时序图 |
| 系统由哪些组件组成,组件之间如何依赖 | 组件图 |
| 服务、组件、数据库部署在哪些机器或节点上 | 部署图 |
| 用户或外部系统能使用哪些功能 | 用例图 |
| 一个业务对象有哪些状态,状态如何迁移 | 状态图 |
| 一个业务流程如何流转,分支和泳道如何划分 | 活动图 |
类图:描述静态结构
类图用来表达类的属性、方法,以及类之间的静态关系。一个类通常分成三部分:类名、属性、方法。
图中每个类都是一个静态结构单元,连线表示类之间的关系。类图尤其适合领域建模、核心对象设计、数据模型讨论等场景。
常见关系可以这样理解:
| 关系 | 含义 | 例子 |
|---|---|---|
| 关联 | 一个类长期知道另一个类 | 用户拥有多个订单 |
| 依赖 | 一个类临时使用另一个类 | 订单服务调用支付工具类 |
| 聚合 | 整体包含部分,部分可以独立存在 | 部门包含员工 |
| 组合 | 整体包含部分,部分不能脱离整体存在 | 订单包含订单明细 |
| 泛化 / 继承 | 子类继承父类能力 | 会员用户继承普通用户 |
| 实现 | 类实现接口约定 | 支付服务实现支付接口 |
用 Mermaid 可以快速写出一个简化类图:
classDiagram
class User {
+Long id
+String name
+createOrder()
}
class Order {
+Long id
+Money amount
+pay()
+cancel()
}
class Payment {
+pay(orderId, amount)
}
User "1" --> "0..*" Order : creates
Order ..> Payment : depends on
类图不要画成数据库表结构大全。它更关注业务对象之间的关系,而不是把每个字段都列全。
时序图:描述动态调用顺序
类图是静态关系,时序图关注动态过程。一次登录、一次下单、一次支付回调,都可以用时序图表达调用顺序。
时序图里,每个参与者都有一条从上到下的生命线,消息箭头按时间顺序排列。细长的激活条表示参与者正在处理某个调用。
一个下单流程可以简化成这样:
sequenceDiagram
participant U as 用户
participant O as 订单服务
participant S as 库存服务
participant P as 支付服务
U->>O: 提交订单
O->>S: 锁定库存
S-->>O: 库存锁定成功
O->>P: 创建支付单
P-->>O: 返回支付链接
O-->>U: 返回下单结果
时序图适合讨论接口调用、异常分支、超时重试、消息异步处理。画时序图时要注意两点:时间方向必须清晰,参与者粒度要一致,不要把“服务”“方法”“数据库表”混在同一层级。
组件图:描述模块和依赖
组件比类的粒度更大,一个组件可能包含多个类、包或服务。组件图常用来说明系统拆分、模块边界和依赖方向。
在工程实践里,组件可以是一个服务、一个模块、一个 JAR(Java 归档包)、一个 DLL(动态链接库),也可以是一个独立部署的业务子系统。
组件图重点关注“谁依赖谁”,而不是一次调用的具体顺序。如果要表达调用先后,应该改用时序图。
组件图可以用于回答这些问题:
- 哪些模块属于同一个系统;
- 哪些模块可以独立发布;
- 哪些组件被多个业务复用;
- 哪些依赖可能形成循环;
- 哪些模块是核心稳定层,哪些模块变化频繁。
部署图:描述物理运行环境
部署图描述软件最终运行在哪些节点上,包括服务器、容器、数据库、中间件、第三方系统等。
部署图适合在方案评审、资源评估、运维交接时使用。它能让相关人员理解系统的物理形态:需要多少机器,服务如何分布,数据库和缓存部署在哪里,第三方系统从哪个网络边界访问。
部署图通常要标清楚:
| 元素 | 说明 |
|---|---|
| 节点 | 服务器、容器集群、云服务、边缘节点 |
| 构件 | 部署在节点上的应用、服务、任务 |
| 网络关系 | 内网调用、公网访问、专线、负载均衡 |
| 数据存储 | 数据库、缓存、对象存储、搜索引擎 |
| 外部依赖 | 支付平台、短信平台、认证系统等 |
部署图不要和组件图混淆。组件图关心软件结构,部署图关心物理承载。
用例图:描述系统功能边界
用例图从使用者视角描述系统能提供哪些能力。图中的小人是角色,角色可以是人,也可以是外部系统;矩形框表示系统边界;椭圆表示用例,也就是系统提供的功能。
用例图适合需求讨论阶段使用。它不关心系统内部怎么实现,只关心谁能使用什么功能,以及功能之间是否存在包含、扩展或依赖关系。
例如一个酒店预订系统,可以有这样的用例:
flowchart LR
User[用户] --> Search((查询酒店))
User --> Book((预订房间))
User --> Pay((支付订单))
Merchant[酒店运营人员] --> Manage((管理房态))
Merchant --> Confirm((确认订单))
Pay -.包含.-> Book
用例图最容易出现的问题是粒度失控。一个用例应该表达用户可感知的完整目标,例如“预订房间”,而不是“点击确认按钮”“校验手机号”这种实现细节。
状态图:描述对象生命周期
状态图用于表达单个对象在生命周期内经历哪些状态,以及什么事件会触发状态迁移。订单、账号、优惠券、工单、设备、合同等对象都适合用状态图建模。
状态图的价值在于把散落在需求文档、接口说明、异常处理里的状态规则集中起来。对订单这类核心对象来说,状态迁移一旦不清楚,代码实现和测试用例都会出现漏洞。
一个简化订单状态可以这样表达:
stateDiagram-v2
[*] --> Created: 创建订单
Created --> Paid: 支付成功
Created --> Cancelled: 用户取消 / 超时关闭
Paid --> Delivering: 开始履约
Delivering --> Completed: 履约完成
Paid --> Refunding: 发起退款
Refunding --> Refunded: 退款成功
Completed --> [*]
Cancelled --> [*]
Refunded --> [*]
状态图要避免只画状态、不画触发事件。真正有价值的信息往往是“什么条件下允许从 A 状态变成 B 状态”。
活动图:描述流程和泳道
活动图适合描述业务流程、审批流、跨系统协作流程。它和传统流程图很接近:实心圆表示开始,圆角矩形表示活动,菱形表示判断,终止节点表示结束。
活动图里一个很重要的概念是泳道。泳道用于区分活动归属,可以按角色、系统、部门或业务域划分。泳道清楚以后,流程责任边界也会更清楚。
例如一个简化的退款流程:
flowchart TB
Start((开始)) --> A[用户提交退款申请]
A --> B{订单是否允许退款}
B -- 否 --> C[返回不可退款原因]
B -- 是 --> D[售后系统创建退款单]
D --> E[支付系统执行原路退款]
E --> F{退款是否成功}
F -- 是 --> G[订单状态改为已退款]
F -- 否 --> H[进入人工处理]
G --> End((结束))
C --> End
H --> End
活动图适合把“业务怎么走”讲清楚,但不适合表达类之间的静态关系,也不适合表达部署拓扑。
如何选择合适的图
很多架构图画不好,并不是画图能力不足,而是图类型选错了。可以按表达目标选择:
| 场景 | 推荐图类型 | 不建议使用 |
|---|---|---|
| 讲系统整体能力 | 分层架构图、组件图 | 类图 |
| 讲业务需求边界 | 用例图 | 部署图 |
| 讲一次请求链路 | 时序图 | 用例图 |
| 讲模块拆分和依赖 | 组件图 | 活动图 |
| 讲机器和服务部署 | 部署图 | 类图 |
| 讲对象状态流转 | 状态图 | 组件图 |
| 讲跨角色流程 | 活动图 | 类图 |
同一个系统通常需要多张图,而不是一张图解决所有问题。系统总览图负责建立全局理解,组件图负责说明模块边界,时序图负责解释关键链路,部署图负责说明运行环境。每张图只回答一个主要问题,表达会更清楚。
常见错误和修正方法
| 常见错误 | 结果 | 修正方法 |
|---|---|---|
| 所有信息塞进一张图 | 元素密集,重点消失 | 拆成总览图、组件图、时序图、部署图 |
| 箭头没有含义 | 看不出是调用、依赖还是数据流 | 增加图例,统一箭头方向和线型 |
| 粒度混乱 | 服务、类、表、按钮混在一起 | 同一张图只保留同一级别元素 |
| 颜色随意使用 | 看图人误解颜色含义 | 控制颜色数量,给颜色加图例 |
| 边界不清 | 不知道哪些属于当前系统 | 使用边框区分系统内外、团队内外、云上云下 |
| 术语不一致 | 同一模块被理解成多个东西 | 建立统一命名,和代码仓库、服务名保持对应 |
| 只画正常流程 | 异常、超时、补偿被遗漏 | 为关键链路补充异常分支或单独画异常流程 |
实用检查清单
画完一张架构图后,可以按这份清单检查:
- 图有没有标题,标题是否说明了范围和目的;
- 看图人能不能在 10 秒内找到核心链路;
- 模块边界是否清楚,外部系统是否放在边界之外;
- 箭头方向是否统一,箭头含义是否明确;
- 同一层级的元素粒度是否一致;
- 颜色、图形、线型是否有固定含义;
- 是否遗漏关键依赖、关键数据存储、关键外部系统;
- 是否存在循环依赖或不合理跨层调用;
- 图例、注解、缩写解释是否齐全;
- 目标对象不听讲解时,能否说出图表达的核心意思。
工具选择
拖拽式画图工具适合快速沟通,在线工具 diagrams.net 就能完成大多数架构图、流程图、部署图。需要把图和代码仓库一起维护时,也可以使用 Mermaid 这类文本化画图方式,把图形描述写进 Markdown 文档中。
无论使用哪种工具,重点都不是符号多标准,而是表达准确。架构图是一种沟通语言,最终目的不是展示画图技巧,而是让系统边界、模块职责、调用关系和运行形态被准确理解。








