时序图栏目 ·

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 serviceOrderSvc(读者会怀疑是不是三个东西)
  • “客户端/服务端”过于笼统,最好写到具体边界(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

所以你在团队里可以落一个最小规范:

  1. 文档标题默认写:序列图(Sequence Diagram)
  2. 口头交流允许说“时序图”,但第一次出现时写:时序图(Sequence Diagram)
  3. 如果真要画 Timing Diagram:明确写“计时图(Timing Diagram)”,不要只写“时序图”

这样做的好处是:

  • 对新人友好
  • 对跨团队协作友好
  • 搜索/知识库检索也更稳定(“序列图”关键词更明确)

5)最小规范:一张“看起来专业”的序列图至少要满足什么?

下面这份清单,适合你在写设计文档、接口文档、测试用例时直接套。

5.1 范围规范:一张图只解决一个问题

推荐你在图标题里写清“边界与目标”,例如:

  • “订单支付成功回调(含重复回调/幂等/补偿)”
  • “登录(含验证码、失败重试、风控分支)”

一张图里同时讲“登录 + 注册 + 找回密码 + 设备绑定”,读者只会迷路。

5.2 参与者规范:只放对理解有贡献的对象

常见两种过度:

  • 过少:只画 ClientServer,把真正的复杂性(风控、短信、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:把“流程图”画成“序列图”

症状:

  • 只有一个参与者(或两个“客户端/服务端”)
  • 每一步都是“业务步骤描述”

例如(不推荐):

  • 用户提交订单
  • 系统校验库存
  • 系统扣减库存
  • 系统生成订单

问题:

  • 这更像流程图/活动图
  • 你看不出“谁和谁交互”、哪里是外部依赖、哪里会超时

修正方法:

  1. 把参与者补齐到“交互边界”:AppGatewayOrderServiceInventoryServiceDBMQ
  2. 把步骤改成“消息”:ReserveStock()CreateOrder()Publish(OrderCreated)
  3. 把不确定性补出来:超时、重试、补偿、幂等等

反例 2:分支没有条件,只写“成功/失败”

症状:

  • alt 成功 / 失败
  • 失败分支里包含:参数错、签名错、超时、重复回调、风控拒绝……

问题:

  • 测试没法据此设计用例
  • 研发没法据此统一错误码/重试策略
  • 运营/产品也不知道“失败到底是什么失败”

修正方法:按“触发条件”拆分支。

举个支付回调更像工程的拆法:

  • alt [签名校验失败] → 记录审计 + 返回失败(不重试/或由上游重试)
  • else [订单不存在] → 告警 + 返回失败
  • else [已处理过(幂等命中)] → 直接返回成功
  • else [金额不一致] → 告警 + 冻结订单 + 返回失败
  • else [正常] → 更新订单状态 + 发MQ + 返回成功

你会发现:一旦条件写清,“系统应该怎么做”就变得可讨论、可实现、可测试。


7)落地:写文档/画图时的“先后顺序”(不容易画废)

如果你经常需要把需求或联调内容变成序列图,按这个步骤做,成功率很高:

  1. 先列参与者:谁发起、谁接收、外部依赖有哪些
  2. 写主成功路径:从触发到最终落库/发事件
  3. 补关键分支:参数非法、权限不足、风控拦截、库存不足等
  4. 补不确定性:超时、重试、幂等、补偿、并发
  5. 最后才是美观:对齐、注释、颜色、导出

如果你想把“文字交互”快速变成图,而不是在画图工具里反复拖拽:

  • 可以用「时序图生成器」这种“结构化编辑”方式:
    • 左侧编辑器里按元素点选:生命线 / 消息 / 组合片段(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”,非常好用:

  1. 标题是否写清“场景 + 边界”(这张图解决什么问题)?
  2. 参与者是否命名一致、粒度合适(服务/系统级,不要混成一锅)?
  3. 主成功路径是否完整(从触发到落库/发事件/返回)?
  4. 是否把关键外部依赖画出来(短信、风控、支付、MQ、DB)?
  5. 同步/异步是否区分清楚(箭头语义一致)?
  6. alt/opt/loop/par 是否写清 Guard 条件?
  7. 是否把“不确定性”补齐:超时、重试、幂等、补偿、并发?
  8. 返回消息是否只保留“会影响控制流”的关键返回?
  9. 是否避免把流程图硬塞进序列图(只有一个参与者、全是步骤)?
  10. 是否避免把代码实现细节全部展开(读者不需要知道每个内部方法)?
  11. 是否能从图中直接抽出测试用例(主流程 + 分支 + 异常)?
  12. 图是否可交付(导出清晰、字号可读、在文档里不糊)?

如果你发现自己总是在第 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:有没有办法把文字快速变成可维护的序列图?

有两条路:

  1. 文本 DSL(如 PlantUML)——适合喜欢写代码、放进仓库版本管理的人
  2. 结构化可视化编辑器——适合多数团队协作:左侧点选生命线/消息/组合片段,右侧实时预览,自动排版,并可导出 SVG/PNG/JPEG/draw.io

如果你更偏“文档交付 + 团队可维护”,可以直接试试这个在线生成器:

手打时序图 - 时序图在线制作


结语:把“术语”讲清,时序图才会真的帮你省时间

序列图(Sequence Diagram)真正的价值不是“画得好看”,而是把跨系统交互中最容易漏的东西(分支、异常、不确定性)用一种可讨论的方式固定下来。

你只要做到两件事,就已经比大多数“看起来有图但没信息”的文档强很多:

  • 在标题/首次出现处明确:这是 Sequence Diagram(序列图/时序图),不是 Timing Diagram
  • 用最小规范表达:参与者边界 + 分支条件 + 超时/重试/幂等/补偿

剩下的就是:让图变得更容易维护、更容易导出、更容易被团队复用。