UML 时序图是什么:和“时序图/序列图”是不是一回事?术语与规范一次讲清
很多人把时序图、序列图、UML 时序图混着叫,结果文档里一半人在画消息交互,一半人在画信号随时间变化。本文用研发/测试/架构写文档的视角,把术语、核心元素、最小规范、常见误解与落地清单一次说清。
很多人问“UML 时序图是什么”,真正困扰通常不是“会不会画箭头”,而是:
- 文档里写“时序图”,到底是指 UML Sequence Diagram(序列图/时序图),还是指 UML Timing Diagram(计时图/时间图)?
- “时序图”和“序列图”是不是一回事?为什么不同团队叫法不一样?
- 画的时候哪些是规范,哪些只是画图工具的风格?
如果你做产品/研发/测试/架构,或者经常写接口说明、联调文档、事故复盘,这篇文章给你一个可直接落地的结论:
大多数中文语境里说的“时序图”,99% 指的是 UML 的 Sequence Diagram(序列图)。 它用“时间从上到下”的方式,表达多个参与者(人/服务/组件/对象)之间的消息交互顺序。
但在 UML 里,“Timing Diagram”也常被翻译成“时序图/计时图”。它关注的是某个对象的状态/信号值随时间变化,不是消息交互。
下面我按“术语 → 规范 → 反例 → 清单 → FAQ”的顺序,帮你把坑填平。
1)UML 时序图到底指什么?先把术语对齐
1.1 UML 官方叫法:Sequence Diagram(序列图)
UML(Unified Modeling Language,统一建模语言)里有很多图。你在研发文档里经常用到的那种“竖线 + 箭头 + alt/loop”的交互图,规范名称是:
- Sequence Diagram(序列图)
中文翻译历史上有两种常见叫法:
- 序列图:更贴近英文 sequence(序列)
- 时序图:强调时间顺序(从上到下)
所以在不少公司/教材里:
- “时序图”≈“序列图”≈“UML Sequence Diagram”
这也是你看到同一个东西被叫成两三个名字的根源。
1.2 另一个也被叫“时序图”的:Timing Diagram(计时图/时间图)
UML 里还有一种图:
- Timing Diagram(计时图/时间图)
它画的是:
- 一个或多个对象的状态(或信号值)随时间变化
例如:
- 设备从
IDLE → BUSY → ERROR的状态持续时间 - 某条信号线电平
0/1在时间轴上的变化
注意它的关注点不是“谁调用了谁”,而是“这个东西在时间上经历了什么状态/值变化”。
很多中文资料把 Timing Diagram 也翻译成“时序图”,这就造成了混淆:
- 你以为同事要你画“调用顺序”
- 同事以为你要画“状态随时间变化”
解决办法很简单:在文档里第一次出现时,写全称:
- “本节给出 UML Sequence Diagram(序列图/时序图)”
- 或“本节给出 UML Timing Diagram(计时图)”
如果你只写“时序图”,建议在团队约定里明确:默认指 Sequence Diagram。
1.3 你在项目里常见的三种“时序图”说法(建议用法)
给一个务实的命名建议(适合写 PRD/设计文档/测试用例):
- 序列图(Sequence Diagram):跨角色/跨服务的交互顺序(最常用)
- 状态图(State Machine Diagram):一个对象在事件驱动下的状态迁移(比如订单状态)
- 计时图(Timing Diagram):状态/信号随时间的持续与切换(偏嵌入式/协议/性能时序)
如果你想减少沟通成本:
- 口头叫“时序图”可以
- 落在文档标题里尽量写“序列图(UML Sequence Diagram)”,很少有人会误解
2)Sequence Diagram(序列图)表达的是什么?不表达的是什么?
先用一句话定义它的边界:
序列图用来说明“多个参与者之间的交互协议”——谁先发起、发什么消息、对方怎么响应、哪些分支/重试/并发会发生。
2.1 特别适合的场景(研发/测试/架构最常用)
- 接口联调:A 服务调 B 服务,B 再调 C,涉及超时、重试、回滚
- 异步回调:支付回调、消息队列消费、Webhook
- 风控/验证码/限流:分支很多,口头说容易漏
- 幂等/去重:重复请求、重复回调的处理路径
- 跨团队协作:把“对方依赖我什么、我依赖对方什么”说清
- 测试设计:从交互路径直接抽测试用例(主流程 + 分支 + 异常)
2.2 不适合/不该用序列图硬画的场景
- 只描述单个模块内部算法(例如排序、匹配、策略计算)
- 用流程图、伪代码、时序日志更合适
- 只想表达“业务步骤”(例如“用户下单 → 填地址 → 付款 → 完成”)
- 用流程图/泳道图更直观
- 想表达“一个对象的状态迁移”
- 用状态图(State Machine)更准确
一句话判断:
- 你关心的是“消息交互”→ 画序列图
- 你关心的是“状态变化”→ 画状态图/计时图
- 你关心的是“步骤/流程”→ 画流程图/活动图
3)序列图核心元素:你需要掌握的最小集合
你不需要把 UML 规范背下来,但至少要把“别人看到不会误解”的最低标准掌握。
3.1 参与者(Actor)与生命线(Lifeline)
- 参与者:人、外部系统、服务、组件、对象……只要它在交互里“发/收消息”就算
- 生命线(Lifeline):参与者在时间轴上的存在(通常是一条竖虚线)
命名建议(非常实用):
- 人/角色:
User/运营/管理员 - 服务:
OrderService/PaymentService - 外部系统:
支付宝/短信网关/风控系统 - 资源/存储:
DB/Redis/MQ
别犯的坑:
- 同一张图里同时出现
订单服务、order service、OrderSvc(读者会怀疑是不是三个东西) - “客户端/服务端”过于笼统,最好写到具体边界(App、Web、Gateway、具体服务)
3.2 消息(Message):同步、异步、返回、创建/销毁
序列图的箭头不是装饰,它表达的是语义:
- 同步消息(Synchronous):调用方发出请求并等待结果(常见:HTTP/RPC)
- 异步消息(Asynchronous):发出后不等待返回(常见:MQ、事件发布)
- 返回消息(Return):可画可不画,关键在于“是否会造成误解”(下文会讲)
命名建议:
- 用“动词 + 名词”或“方法签名”表达意图:
CreateOrder(req)VerifyCaptcha()Publish(OrderPaid)
3.3 激活条(Activation):谁在“占用执行”
激活条(也叫执行规格 Execution Specification)是生命线上的长条,用来表示:
- 该参与者在这段时间内“正在处理”
它的价值在于:
- 让读者看出“谁在等谁”、是否存在阻塞
- 让并发/嵌套更清晰
常见误解:
- 激活条画得越长越专业(不对,长度应与处理跨度一致,且要服务于理解)
3.4 组合片段(Combined Fragment):分支/循环/并行的规范表达
你在项目里最常用的四个:
alt:分支(if/else)opt:可选分支(只有 if,没有 else)loop:循环(重试、分页、多次尝试)par:并行(并发调用、并行任务)
写清楚“条件”(Guard)非常关键:
alt [验证码正确]/else [验证码错误]loop [最多重试 3 次 且 未超时]
只画一个大框写“异常情况”是最容易误解的:异常到底包含哪些?触发条件是什么?
4)“时序图”和“序列图”是不是一回事?给一个工程化答案
在工程实践里,你可以这样理解:
- 当上下文没有特别说明:
- “时序图”=“序列图”=“UML Sequence Diagram”
- 当上下文涉及信号/状态随时间变化(例如通信协议、硬件、性能时序):
- “时序图”可能指 Timing Diagram
所以你在团队里可以落一个最小规范:
- 文档标题默认写:序列图(Sequence Diagram)
- 口头交流允许说“时序图”,但第一次出现时写:时序图(Sequence Diagram)
- 如果真要画 Timing Diagram:明确写“计时图(Timing Diagram)”,不要只写“时序图”
这样做的好处是:
- 对新人友好
- 对跨团队协作友好
- 搜索/知识库检索也更稳定(“序列图”关键词更明确)
5)最小规范:一张“看起来专业”的序列图至少要满足什么?
下面这份清单,适合你在写设计文档、接口文档、测试用例时直接套。
5.1 范围规范:一张图只解决一个问题
推荐你在图标题里写清“边界与目标”,例如:
- “订单支付成功回调(含重复回调/幂等/补偿)”
- “登录(含验证码、失败重试、风控分支)”
一张图里同时讲“登录 + 注册 + 找回密码 + 设备绑定”,读者只会迷路。
5.2 参与者规范:只放对理解有贡献的对象
常见两种过度:
- 过少:只画
Client→Server,把真正的复杂性(风控、短信、DB、MQ)藏掉 - 过多:把所有内部类/方法都摆上去,变成“代码级时序图”,阅读成本爆炸
经验建议:
- 设计/联调文档:参与者粒度到“服务/系统/关键组件”即可
- 代码评审/实现细节:可以另补“局部序列图”到类/模块级
5.3 消息规范:把“协议”说清,而不是把“函数调用”抄一遍
好的消息应该让读者知道:
- 这是什么请求(意图)
- 关键输入/输出是什么(只写关键字段)
- 同步还是异步
反例(读者看完仍然不知道发生了什么):
doProcess()handle()call()
更好的写法:
POST /pay/callback (orderId, amount, sign)VerifySign(payload)UpdateOrderStatus(PAID)
5.4 分支规范:条件要写在框上,不要藏在文字里
alt/opt框上的 Guard(条件)是“规范信息”,不是注释loop建议写清上限或退出条件:次数/时间/幂等键
反例:
- 一个
alt框写“失败情况”,里面塞十几条箭头
修正:
- 按触发条件拆:
[签名非法]、[订单不存在]、[已处理过]、[支付金额不匹配]
5.5 返回消息到底要不要画?(工程建议)
你会看到两种风格:
- 画返回虚线箭头(return message)
- 不画返回,只在下一条消息继续向下
我的建议(偏工程落地):
- 当“返回值影响后续路径”时画出来(例如返回码决定是否重试、是否补偿)
- 当返回只会制造噪音时省略(例如每个 HTTP 都画 200 OK,会让图变成梳子)
一个常见折中:
- 只画关键的返回:错误码、超时、拒绝、风控拦截
6)两个常见反例:为什么“看起来对”但不专业?(含修正)
反例 1:把“流程图”画成“序列图”
症状:
- 只有一个参与者(或两个“客户端/服务端”)
- 每一步都是“业务步骤描述”
例如(不推荐):
- 用户提交订单
- 系统校验库存
- 系统扣减库存
- 系统生成订单
问题:
- 这更像流程图/活动图
- 你看不出“谁和谁交互”、哪里是外部依赖、哪里会超时
修正方法:
- 把参与者补齐到“交互边界”:
App、Gateway、OrderService、InventoryService、DB、MQ - 把步骤改成“消息”:
ReserveStock()、CreateOrder()、Publish(OrderCreated) - 把不确定性补出来:超时、重试、补偿、幂等等
反例 2:分支没有条件,只写“成功/失败”
症状:
alt 成功 / 失败- 失败分支里包含:参数错、签名错、超时、重复回调、风控拒绝……
问题:
- 测试没法据此设计用例
- 研发没法据此统一错误码/重试策略
- 运营/产品也不知道“失败到底是什么失败”
修正方法:按“触发条件”拆分支。
举个支付回调更像工程的拆法:
alt [签名校验失败]→ 记录审计 + 返回失败(不重试/或由上游重试)else [订单不存在]→ 告警 + 返回失败else [已处理过(幂等命中)]→ 直接返回成功else [金额不一致]→ 告警 + 冻结订单 + 返回失败else [正常]→ 更新订单状态 + 发MQ + 返回成功
你会发现:一旦条件写清,“系统应该怎么做”就变得可讨论、可实现、可测试。
7)落地:写文档/画图时的“先后顺序”(不容易画废)
如果你经常需要把需求或联调内容变成序列图,按这个步骤做,成功率很高:
- 先列参与者:谁发起、谁接收、外部依赖有哪些
- 写主成功路径:从触发到最终落库/发事件
- 补关键分支:参数非法、权限不足、风控拦截、库存不足等
- 补不确定性:超时、重试、幂等、补偿、并发
- 最后才是美观:对齐、注释、颜色、导出
如果你想把“文字交互”快速变成图,而不是在画图工具里反复拖拽:
- 可以用「时序图生成器」这种“结构化编辑”方式:
- 左侧编辑器里按元素点选:生命线 / 消息 / 组合片段(alt/opt/loop/par)
- 右侧实时预览,边改边看效果
- 自动排版减少手工对齐
- 最终可直接导出 SVG/PNG/JPEG/draw.io,方便你塞进文档或继续二次编辑
(需要的话你可以直接试一下: 手打时序图 - 时序图在线制作 )
8)一个小例子:把“登录”画成序列图时,哪些信息值得出现?
很多登录图画得空,是因为只画了:Client → Server: login()。
更接近工程落地的做法是把“可变部分”补出来:
- 是否需要验证码?触发条件是什么?
- 密码错误是否计数?是否触发风控?
- 失败是否可重试?间隔?上限?
- token 签发在哪个组件?是否需要刷新 token?
你不必把每个字段都写在箭头上,但至少要把“会改变控制流的判断”表达出来。
例如(PlantUML 伪代码,仅演示结构):
@startuml
actor User
participant App
participant Gateway
participant AuthService
participant RiskService
participant CaptchaService
User -> App: 输入账号密码
App -> Gateway: POST /login
Gateway -> AuthService: Login(username, pwd, device)
AuthService -> RiskService: Evaluate(device, ip, user)
alt [风险高]
AuthService -> CaptchaService: RequireCaptcha()
CaptchaService --> AuthService: captchaToken
AuthService --> Gateway: 401 NEED_CAPTCHA
else [风险低]
AuthService --> Gateway: 200 token
end
Gateway --> App: 返回结果
App --> User: 展示/进入首页
@enduml
这里的重点不是语法,而是:
alt的条件写清楚- 风控/验证码是独立参与者(边界清晰)
- 返回码影响下一步(所以返回值得画)
9)检查清单:画完一张序列图,你可以自检这 12 项
把这 12 项当成“评审时的 checklist”,非常好用:
- 标题是否写清“场景 + 边界”(这张图解决什么问题)?
- 参与者是否命名一致、粒度合适(服务/系统级,不要混成一锅)?
- 主成功路径是否完整(从触发到落库/发事件/返回)?
- 是否把关键外部依赖画出来(短信、风控、支付、MQ、DB)?
- 同步/异步是否区分清楚(箭头语义一致)?
alt/opt/loop/par是否写清 Guard 条件?- 是否把“不确定性”补齐:超时、重试、幂等、补偿、并发?
- 返回消息是否只保留“会影响控制流”的关键返回?
- 是否避免把流程图硬塞进序列图(只有一个参与者、全是步骤)?
- 是否避免把代码实现细节全部展开(读者不需要知道每个内部方法)?
- 是否能从图中直接抽出测试用例(主流程 + 分支 + 异常)?
- 图是否可交付(导出清晰、字号可读、在文档里不糊)?
如果你发现自己总是在第 12 条踩坑:
- 优先选支持自动排版与高清导出的工具(SVG 最适合文档)
- 或者用支持导出 draw.io 的方式,让团队后续能继续维护同一份图
10)FAQ:你可能会遇到的 8 个高频问题
Q1:我在文档里写“时序图”,别人总理解不一致,怎么办?
建议第一处写成:
- “时序图(UML Sequence Diagram,序列图)”
如果你要表达 Timing Diagram:
- 写“计时图(UML Timing Diagram)”
并在团队模板里固定下来(最省心)。
Q2:序列图一定要完全符合 UML 规范吗?
不一定。工程文档更看重“可读、可讨论、可实现、可测试”。
但有三类信息最好别省:
- 参与者边界(谁和谁交互)
- 分支条件(为什么走这条路)
- 异常与不确定性(超时/重试/幂等/补偿)
Q3:返回虚线箭头到底要不要画?
按“是否会影响后续”来决定:
- 会影响(错误码、超时、拒绝、风控)→ 画
- 不影响(每个请求都 200 OK)→ 省略
Q4:我能不能把 DB、缓存、MQ 也当参与者?
可以,而且常常应该。
原因:它们是交互链路里的关键依赖,决定了延迟、失败模式与一致性策略。
Q5:序列图里怎么表达重试与幂等?
- 重试:用
loop [最多 N 次/直到超时],并标注间隔/退避策略(如果重要) - 幂等:在分支里明确条件:
alt [幂等键已处理] → 直接返回成功
Q6:怎么表达并发?
- 用
par并行片段 - 或在消息旁标注“async”并用异步箭头
如果并发很复杂,建议拆成两张图:
- 一张讲“控制面”(谁触发谁)
- 一张讲“数据面”(并发任务的汇聚/一致性)
Q7:学生作业要写“UML 时序图”,我用工具生成行不行?
通常没问题。评分更看重:
- 参与者是否合理
- 消息命名是否准确
- 分支/循环是否表达清楚
但别直接生成一张“看起来很复杂”的图——老师往往更在意“你是否理解每条箭头的含义”。
Q8:有没有办法把文字快速变成可维护的序列图?
有两条路:
- 文本 DSL(如 PlantUML)——适合喜欢写代码、放进仓库版本管理的人
- 结构化可视化编辑器——适合多数团队协作:左侧点选生命线/消息/组合片段,右侧实时预览,自动排版,并可导出 SVG/PNG/JPEG/draw.io
如果你更偏“文档交付 + 团队可维护”,可以直接试试这个在线生成器:
结语:把“术语”讲清,时序图才会真的帮你省时间
序列图(Sequence Diagram)真正的价值不是“画得好看”,而是把跨系统交互中最容易漏的东西(分支、异常、不确定性)用一种可讨论的方式固定下来。
你只要做到两件事,就已经比大多数“看起来有图但没信息”的文档强很多:
- 在标题/首次出现处明确:这是 Sequence Diagram(序列图/时序图),不是 Timing Diagram
- 用最小规范表达:参与者边界 + 分支条件 + 超时/重试/幂等/补偿
剩下的就是:让图变得更容易维护、更容易导出、更容易被团队复用。