引子:一张用例图,救了一个快失控的项目
接手那个后台管理系统项目的时候,需求讨论已经进行了整整三周,会议室的白板换了三次颜色,群里消息超过两千条。可你问任何一个开发同学"这系统到底要给谁用、用在哪、怎么用",没人能给你一个完整答案。大家手上有的是零散的功能清单:管理用户、导入数据、生成报表……每一条都像从某个Excel表格里粘出来的孤岛。
后来我们做了一件事:停下来,把所有人拉到会议室,用一下午时间画了一张用例图。就一张图,十几条椭圆,几条连线。神奇的是,争论了三周的问题一下变得具体了——"运营人员到底要不要审核这条数据?""这个功能是给店长用的还是给客服用的?"——图上画得清清楚楚。从那以后,我基本判断一个需求分析兜不兜得住底,就看他手里有没有一套像样的用例。
这篇内容就是聊聊我在实际项目中应用"需求与设计过程"里的用例方法时积累的经验,从概念拆解到实操模板,再到现在回看哪些坑是新人最容易踩进去的。如果你是刚从开发切到需求分析的同学,或者一直用"用户故事"但觉得轻飘飘、覆盖不够的同学,这篇可以当个落地参考。
1. 需求与设计过程中,用例到底承担什么角色
1.1 用例不是画图,是一种思维方式
很多人一听"用例"第一反应是UML里的那种椭圆加小人图形。图当然没错,但图只是表达媒介,真正的用例是一套思维方式:从"系统该有什么功能"转向"外部角色想通过系统达成什么目标"。
这样扭转的意义有多大?举个例子,一个在线商城项目,需求方提了一堆:商品管理、订单管理、库存管理、优惠券管理、支付对接。你要是按这个功能列表去设计,出来的是一个"功能树",每种功能一个模块,模块之间靠什么衔接?不知道。页面上要放什么按钮?猜。数据从一个状态到另一个状态怎么流转?靠想象。
如果用用例思考,同样这个商城,你会先问:谁在用系统?购物的用户(下单、查订单、退换货)、运营人员(管理商品、处理退款)、系统管理员(设置权限)。然后问:这些人分别拿系统要达成什么目标?用户的下单、运营的审核、管理员的权限分配,这些都是用例。再看用例之间关系,"用户下单"包含"验证库存""扣减库存""生成订单",这是include关系。这样,功能的边界、前置、后置、异常,整个链条就出来了。
1.2 用例在需求分析流程中的位置
从流程上看,需求与设计大致是这么个链条:业务调研 -> 用户画像 -> 业务流程梳理 -> 功能需求提取 -> 系统分析 -> 概要设计 -> 详细设计。用例前面接的是业务流程图和作用域分析,后面接的是用例实现(比如用时序图、活动图或状态机去描述系统内部行为)。
一句话概括:业务流程图描述的是"业务怎么做",用例描述的是"系统怎么被使用"。前者可能涉及线下的手工步骤、审批流程里干系人签字之类,后者只关注系统和系统外部角色之间的交互。很多分析人员在这两步之间跳得过快,业务调研完直接画界面原型,结果原型一评审发现漏了一堆角色视角,比如只考虑正向流程,压根没想过"异常情况用户重复提交""并发下库存超卖"这些场景,而用例的扩展流程正好逼你把这类情况提前摆到台面上。
1.3 用例与其他需求方法的区别与互补
也有人问我:敏捷团队都用用户故事,为什么还要用用例?用户故事的好处是轻、快、便于排优先级,它的典型句式是"作为XX角色,我希望能够XX,以便达到XX价值"。但在复杂业务里,尤其涉及多角色协作、状态流转、规则校验的场景,单个用户故事的信息容量撑不住。
比如"管理购物车"这个故事,细问:加入商品时库存不足提示什么?用户登录状态过期后购物车是基于本地还是服务器?改数量时价格联动怎么算?这些分支和约束,用户故事里没有自然承载的位置,而用例的"主成功场景+扩展流程"结构天然可以容纳。实际项目中我把两者结合:迭代规划用用户故事,跨迭代的复杂业务域分析用用例。打个比方,用户故事是建筑里的砖头,用例是结构图纸,你盖高层住宅不能没有图纸。
| 维度 | 用户故事 | 用例 |
|---|---|---|
| 表达粒度 | 轻量,一句话 | 完整场景+分支扩展 |
| 承载信息 | 角色-目标-价值 | 流程步骤+前置后置+异常规则 |
| 适用阶段 | 敏捷迭代快速排期 | 复杂业务域分析与系统设计 |
| 弱项 | 异常分支覆盖不足 | 维护成本较高,文本书写量大 |
2. 用例各要素深挖:不是"参与者+用例+连线"那么简单
2.1 识别参与者:别把"人"和"角色"混为一谈
这是新手最常见的问题。参与者(Actor)不是具体的人,而是与系统交互时的一种角色。一个人可以在不同场景承担多个角色。比如一个用户,他买东西时是"普通会员",进入运营后台审核退款时是"运营专员",其实是同一账号体系下的两套参与视角。如果你在用例图上把"张三"当成参与者,那就废了,换个"李四"你的图就得重画。
识别参与者有个土办法:问系统边界在哪,谁会向系统发起操作,系统会把结果反馈给谁,还有谁会被这个系统间接影响。除了直接交互的用户角色,外部系统也是参与者。比如支付平台、短信通道、第三方地图服务,它们同样在发起用例。漏了外部系统参与者的项目,我见过不少——后来联调的时候才发现,这个操作完了还要调外部接口确认状态,用例描述里根本没这一段,接口该什么时候调用、失败重试几次,全是临时拍脑袋定的。
2.2 用例命名:动词开头,目标导向,拒绝功能按钮式命名
用例名应该是"用户能够完成的一个目标",因此用"动词+宾语"的主动语态,比如"提交退款申请""查看历史订单""导出月度报表"。千万别写成"用户管理"这类名词短语,因为"用户管理"不是目标,是CRUD动作的集合,你不知道是创建用户、停用账号还是修改资料。命名粒度统一也很重要,都是"查看订单列表"、"查询订单详情"这种级别,而不是一个叫"确认收货"一个叫"修改订单地址并通知物流方生成短信验证码并发起后端物流状态同步",悬殊太大,后期图谱很难维护。
2.3 场景与流程:主成功场景之外,扩展流程决定用例质量
一个用例的完整定义应该包含至少三段内容:主成功场景(Main Success Scenario)、扩展/替代流程(Extensions/Alternatives)、异常流程(Exception paths)。
主成功场景是"正常情况下,一次简短、目标明确、没有干扰的交互全程"。很多人写到这里就停了,以为自己写完了用例。事实上用例深度恰恰体现在扩展流程上。拿"支付订单"来说,主流程:用户核对订单金额 -> 选择支付方式 -> 调起支付 -> 系统接收支付成功回调 -> 更新订单状态 -> 完成。看起来没问题,但扩展流程才是业务规则的密集区:
- 余额不足怎么提示?是否允许部分支付?
- 支付过程中用户取消,订单状态回滚还是挂起?
- 回调迟迟未到,订单算已支付还是待支付?补偿查询怎么做?
- 用户重复点击支付按钮,系统如何防重复提交?
- 支付成功后系统异常宕机,消息丢失如何处理?
这些点,凡是做过多系统对接的老开发应该很有共鸣——线上事故十有八九出在这里,而不是主流程。所以用例编写者不能只坐在需求会议桌前听"正常情况",必须追着需求方问"那要是不行呢""要是没反应呢""要是没钱呢",你的扩展流程写得多全,未来开发阶段返工的可能性就有多低。
2.4 前置条件与后置条件:最容易藏着边界问题
前置条件描述的是"用例开始前,系统必须处于什么状态",后置条件描述的是"用例成功结束后,系统处于什么状态"。听起来很学术,但落到实操里意义巨大。
举个例子,"提交退货申请"这个用例的前置条件是"用户已登录,且订单状态为'已收货'",后置条件是"系统生成退货单,状态为'待审核',库存流水记录'退货占用数'+1"。如果你不写这些,开发实现时就会有两种方案:不管订单什么状态都能点退货申请,或者同一个订单能反复提交多个退货申请。写清楚后,开发、测试、评审三方对齐的都是同一套状态闸门,边界问题在需求阶段就收敛了。
2.5 一个能直接抄作业的用例描述模板
我在项目里用的一套模板长这样,经历了多轮迭代,基本覆盖了后续开发要问的大部分问题:
| 字段 | 填写说明 | 示例(以"提交退货申请"为例) |
|---|---|---|
| 用例编号 | UC-XX-XXX,层级编码 | UC-ORD-014 |
| 用例名称 | 动词+目标 | 提交退货申请 |
| 参与者 | 主要参与者+次要参与者 | 主要:普通会员;次要:库存系统 |
| 目标 | 一句话说明用户价值 | 用户可不经客服介入自助发起退货 |
| 触发器 | 什么动作触发用例开始 | 用户在订单详情页点击"申请退货" |
| 前置条件 | 系统状态要求 | 已登录;订单状态=已收货;距签收不超过7天 |
| 后置条件 | 成功后的系统状态 | 退货单状态=待审核;原订单状态=退货处理中 |
| 主成功场景 | 编号步骤列表 | 1. 用户查看可退货商品列表 2. 选择商品并填写退货原因 3. 提交申请 4. 系统校验规则 5. 系统生成退货单并通知库存系统 |
| 扩展流程 | 条件触发+替代步骤 | 2a. 商品不在可退货范围内:隐藏退货按钮,并提示客服联系方式 4a. 校验不通过:提示具体原因,返回上一步 |
| 业务规则 | 对步骤或状态的约束 | 同一商品同一订单只能退货一次;退货数量不得超过实收数量 |
| 特殊需求 | 性能、安全、界面约束 | 页面加载时间小于2秒;操作全程需要HTTPS |
| 相关界面 | 原型链接/截图 | (此处放界面原型) |
3. 从用例到设计:中间那座桥得用稳
3.1 用例图解决的是"有哪些用",用例描述解决的是"怎么用"
项目里这两种产物我们要分开评审,顺序也不能乱。第一轮评审用例图,主要确认边界范围和角色覆盖,约需求方、业务方一起过:是不是这些功能?是不是这些角色?第二轮评审才是完整用例描述,重点看流程细节、规则异常,约需求方、研发负责人、测试负责人一起过。这样做的好处是范围讨论和细节讨论不搅在一起,会议就不会变成"大家为某个按钮的位置争论半小时"。
3.2 将用例映射到功能模块与接口设计
用例识别完成后,我到设计阶段一般做个映射表。用例ID对应功能模块ID,用例中的步骤对应接口。比如"提交退货申请"这个用例的步骤4"系统校验规则",对应后端一个校验接口(或服务方法)的参数与异常定义,与界面上点击按钮无关。这样一来,测试计划可以直接参考映射表制定测试用例的关联矩阵,每个用例映射到的功能模块、接口路径、数据表,在开发自测阶段就能逐一验收。
3.3 从用例到测试用例的推导公式
这条经验比较直接:每一个主成功场景步骤,能推出一条正向测试用例;每一个扩展流程分支,能推出一条反向或分支测试用例;每一条业务规则,至少推出一条等价类/边界值测试用例。所以评价一套用例好不好,先看能推导出多少测试用例,一个"支付订单"用例如果只导出了5条测试用例,扩展流程八成没写够;合格的通常在15条以上。
4. 实操记录:在线商城"用户退款"用例从零到评审
4.1 场景设定
我以最近给某模拟电商平台做的退款流程为例,整个模块并不复杂,但用例前后的差别很清楚。需求方最初给的资料是:一句话"用户能退款",加一个流程图,图上画着"用户申请、商家同意、退款原路返回"。没了。
按这套东西去开发,漏洞至少能列十个:退款后优惠券是否退回?无库存商品退款后是否恢复库存?退款金额是否包含运费?退款流程中商家超过48小时未处理自动怎么走?中国国内支付渠道退款有手续费,谁承担?——全是关键业务决策,原资料一个没提。于是我先列参与者:
- 普通会员:发起退款申请,查看退款进度。
- 客服人员:在消费者投诉或咨询时查询退款状态,必要时介入。
- 商家(运营端):审核退款申请。
- 支付网关:执行原路退款操作,返回退款结果。
- 系统定时任务:超时未审核时自动通过退款申请。
注意我把定时任务也算为了参与者,因为它同样是"主动发起一笔操作的外部角色",这在用例分析和系统实现时的触发机制是对应的。
4.2 用例清单与优先级
- UC-RF-01 提交退款申请(P0)
- UC-RF-02 审核退款申请(P0)
- UC-RF-03 执行退款打款(P0)
- UC-RF-04 查看退款进度(P1)
- UC-RF-05 撤销退款申请(P1)
- UC-RF-06 超时自动审核(P1)
- UC-RF-07 退款失败重试(P1)
标题列出来,需求方一看就反应过来了:原来还有"撤销退款"这个操作,原来退款还可能失败,原来系统得有个自动任务兜底。这比"用户能退款"五个字信息量大太多。
4.3 重点用例连贯描述
以"UC-RF-03 执行退款打款"为例,它是整个链条中最容易被错误设计成普通功能调用的用例。触发条件是"审核通过后,系统收到自动审核通过事件或客服手动确认通过"。前置条件是"退款单状态=待打款;支付网关连接可用"。主成功场景:
- 系统读取退款单及其支付原始凭证。
- 系统调支付网关退款接口,传输退款金额与原因代号。
- 网关返回退款受理确认。
- 系统记录退款流水,状态置为"退款中"。
- 系统接收网关异步退款结果通知,验证签名与金额。
- 系统更新退款单状态为"退款成功",同时回调订单模块标记订单已退款。
- 系统发送站内信/短信通知用户退款进度。
扩展流程我列了四条比较有代表性的:
2a. 网关超时:系统捕获超时后记录重试日志,退单状态保持"待打款",由定时任务每30分钟扫一次,重试上限3次;若仍失败,置为"退款异常"并通知财务人工介入。这条扩展流程直接决定了后端要有一张重试表和定时任务,很多项目因为没写这些,退款单卡死在"退款中"没人管,用户投诉才有人查数据库。
5a. 回调签名验签失败:主动向网关查询退款状态以规避伪造回调;若网关显示失败,则按失败流程处理,并把事件标记为"疑似攻击"告警。这条写上之后,测试组针对回调伪造做了专项用例,联调阶段还真的测出网关侧在自己测试环境没有校验签名导致回调异常的情况。
4.4 评审中讨论出来的关键规则
这个用例评审了两次。第一次只谈主流程,20分钟就过了。我坚持又加了一场,专门过扩展流程。会上问需求方:"用户申请退款时申请了整单退款,但其中一件商品实际已发货未签收,剩下一件还没发货,怎么处理?"需求方愣住了——他们原来的假设是整个订单一起退。最后定下来:可部分退款,但运费按整单原运费1:1分摊,清零优惠券按原比例退回用户账户,有效期延长30天。这些规则后来直接去了开发排期里的改动点。如果不做第二场评审,按原设计实现,用户买到一半少发一半的事故早就上线了。
5. 常见坑位与排查技巧:用例实践中的实战笔记
5.1 粒度失控:要么粗到没法设计,要么细到变成伪代码
用例粒度可以用"一个参与者想达成的一个可观察目标"来界定。粗到什么程度算太粗?"管理订单"这种明显是一个系统模块级别的CRUD集合,应该拆成"创建订单""取消订单""修改地址""导出订单""标记发货"多个用例。细到什么程度算太细?如果步骤里出现"点击页面右侧的'确认'按钮"或者"调用DAO持久层更新数据库",说明你把系统设计阶段的实现细节过早掺进了需求分析。用例步骤要描述的是用户与系统进行到哪个信息交换,而不是界面上的某个控件操作。
5.2 Include和Extend关系被滥用
这两个关系的使用率在大量项目中是这个样子的:画用例图的时候满纸< >,到了描述阶段就不知道包含的是什么了。Include的本质是"你每次执行A,都会执行这个公共步骤B",Extend的本质是"你在执行A的过程中,在特定条件下,可能额外执行一段C"。实操建议:
- Include适合公共步骤,"扣减库存""写入操作日志""校验登录态"。改一处全部生效,这也符合软件设计的DRY原则。
- Extend适合可选扩展,"推送物流信息到短信服务""生成优惠券兑换码",基础用例不依赖扩展用例,而扩展用例在特定条件下插入。
- 凡是一个用例需要"不一定走"的支线,都先考虑Extend;凡是多个用例都调用的公共子步骤,先考虑Include。
有些项目把"支付订单"和"余额支付"画成Extend,倒也不是不能解释,但扩展关系只是说明逻辑,替代性流程我建议放在同一个用例的扩展流程区里,用"条件+步骤"描述,而不是拆成好几个独立用例,否则测试矩阵会膨胀得没法看。
5.3 前置条件写成了操作步骤
前置条件常见的误写是"用户点击申请退款按钮之后"。这不是前置条件,这是触发器。前置条件是系统状态:用户已登录(这是系统状态)、订单已收货(状态描述)、距离签收不超过7天(业务时间窗口)。触发器是哪个事件启动了这个用例。这两个写错,开发在状态机设计时就会把事件的先后顺序搞乱。我自己检查用例描述时,会专门看前置条件里有没有动词,有动词基本就是写错了。
5.4 用例里塞满了业务规则,却没有规则编号
业务规则可能需要被多个用例引用,比如"同一订单只能有一个进行中的退货流程""优惠券只能使用一次且不可叠加"。如果在每个用例描述里重复整段粘贴规则文本,后期修改一个规则就要改十几个文档。我的习惯是把规则抽取到独立的"业务规则清单"文档里,每条规则编号如BR-014,在用例的"业务规则"字段中引用编号即可。开发工时评估和测试点位追踪,都按规则编号来,而不是按用例文本来。
5.5 用例评审忽略了非功能需求
用例模板里的"特殊需求"字段,不能只放界面原型。这该是存储非功能需求的地方:性能(页面响应时间、并发量)、安全(数据加密、权限校验、审计日志)、合规(是否涉及退款时限、隐私协议)。这个字段如果遗留为空,性能指标和验收标准就会在开发测试阶段被默认成"大概两秒能出来",而需求方说"不应该很慢",双方对"很慢"的标准完全不同。至少要把明确的数字或等级写进去,比如"退款结果异步通知的响应时间不超过3秒,回调失败重试间隔为30秒,单日请求量级不低于10万"。写不下再单开一个非功能需求文档,也别留空。
6. 用例文本的编写纪律:八条习惯帮你少挨骂
6.1 编号统一,方便追溯
用例编号就是需求的坐标,必须沿着模块划分稳定统一。某一层是模块编码(ORD订单、PMT支付、USR用户),下一层是业务流水(001、002……),修改一个用例ID就要全文档同步,包括关联的映射表和测试用例矩阵。不一致编号在评审会现场被点出来,气氛往往很尴尬。
6.2 动词状态话术避免歧义
用例描述里"系统返回结果"这种写法是通不过评审的。要让开发不打回票,应该写"系统在响应中返回订单状态为待支付的完整订单对象,字段包括订单号、金额、优惠信息"。所有步骤的表述统一成"参与者动作"与"系统响应"交替出现,描述用户做了什么,系统做了什么,一环扣一环,状态机自然能被推断出来。
6.3 每一条业务规则都能追溯到源头
规则的"源头"可能是某条法律法规、合规要求、运营活动策略、客服历史工单。在规则编号旁注明来源,评审时可以快速核对需求方背书。有些规则是开发从历史代码逆向推断出来的,这类规则要单独标"推断"字样,让需求方确认,否则设计依据不牢靠。
6.4 关联关系保持最小必要
一个用例挂七八个关联用例,图会极其难看,阅读体验极差。若是同一流程的几个用例之间,用流程说明足够,不需要全部连线。"提交申请"与"审核申请"之间有顺序依赖,通常用全景的业务流程图说明先后,用例图只画功能关系,不画时间顺序。
6.5 文档版本管理与变更记录
需求变更不可避免,但每个用例文档要有版本号和变更记录表格。变更了什么、谁提出、影响哪些用例、关联了哪些开发排期任务,全列出来。大版本里我要求需求方确认签核,防止口头说改就改,最后测试和开发拿着不同版本文本来对,那才是真正的灾难。
6.6 明确责任人和评审闭环
每个用例指定一个唯一owner,通常是需求分析师,他负责确保用例内容与最终实现版本一致。评审一定要有结果记录:通过、修改后通过、不通过重讲。只开会不记录结论等同于没开会。这一点在项目进度紧张时最容易偷懒,结果后期扯皮时大家都会说"我记得当时讨论的是……",但没有人能拿出准确记录。
6.7 图片与文字双轨
用例图是很好的速览工具,但细节要靠文字。如果只有图,细节丢了;只有文字,读者找不着全貌。我的原则是:用文字版本作为唯一事实来源,用例图作为附属索引图,随时更新对应。某些团队直接把文字写进原型工具标注里,那也行,前提是你要能做到从任一入口追溯到一致信息。
6.8 拒绝一次性写完整套
规划工具都提倡"滚动式规划"。用例也一样,一期项目识别所有用例并编号,但描述优先级高的用例即可。低优先级角色、偶发场景在迭代二再去补充描述细节。别在某次迭代里试图把整个平台几百个用例全部写满,那样只会让分析瘫痪在文档泥潭中,而需求方早已失去等待耐心。
7. 从用例到任务排期:一条好用的联动路线
7.1 用例分组驱动迭代规划
敏捷迭代的粒度通常以"可交付用户价值"为原则,用例天然是很有用的分块工具。一个用例如果过大,先考虑它能否被拆成"第一阶段部分"和"第二阶段部分",拆不开就宁可拉长排期,也不要切成硬性功能模块后失去语义完整性。
例如"提交退款申请"用例,又可以按支付渠道差别拆成不同的扩展分支,比如微信支付渠道和银行卡渠道不同。第一批可以只支持银行卡渠道,微信支付渠道作为后续增量用例接入。这样用例文档就承载了功能开关的信息,开发团队优先级排序也很清楚。
7.2 用例估算:用相对点数替代绝对工时
给用例估点时,把主成功场景步骤数量与扩展流程数量作为复杂度参考。一个三个步骤且零扩展的用例给1-2点;一个七步主流程加八条扩展的用例给8点以上。相对点数算出来的团队速度更稳定,不会因为人员的编码效率差异产生过大波动。用用例维度来做MVP裁剪也更容易:问"哪些用例没有,系统还能转?"去掉之后剩余的部分就是PMC的最小核心。
7.3 用例与验收标准的对应
当开发完成一个用例对应的全部功能后,测试会基于用例文本做验收:前置条件是否满足,主成功场景走完是否到达后置条件,扩展流程每条是否处理正确。验收结论要记录在用例ID上。这样每个成员随时能知道"这个用例开发完成了、测试通过了、已上线"还是"卡在某个环节"。比散落在IM里的"XX功能做完了"可靠得多。
结语
写到最后,分享一点个人真实感受:用例方法很多时候给人的第一印象是"太重了"。尤其敏捷团队,总觉得用户故事快、用例文档慢。但慢的那部分,省掉的是设计阶段扯皮、开发阶段返工、测试阶段漏测、上线之后投诉处理的时间。我在几个项目里对比过,凡是前期画了完整用例图的,开发中"需求不明确导致返工"的工时占比从明显偏高一路降到一星半点;而凡是赶进度直接画原型开做的,后期每次状态流转出问题都要翻历史记录确认当初有没有人提过类似场景。
如果你刚接触用例,我的建议是从小处起步:挑一个你正在做的中等复杂度功能,写一次完整用例描述,重点放在扩展流程和业务规则上,然后拿去给开发、测试各看一遍,问他们"看完这些你们还有没有疑问"。如果这个功能开发完基本没追问需求细节,你就知道这套方法用得有多值。剩下的事,无非是日复一日地把它变成项目里的肌肉记忆罢了。