1. 从“会画框框”到“讲清需求”:用例图到底解决什么问题
几乎每个做软件需求分析的人,都经历过这种场景:业务方说“我要一个订单管理系统”,开发团队追问“具体有哪些功能”,然后双方在会议室里拉扯半天,发现各自脑子里的系统根本不是同一个东西。需求文档写了几十页,开发看到“系统应支持订单查询”这种描述,依然不知道界面长什么样、数据从哪来、异常怎么处理。
我早年也踩过这个坑,后来慢慢意识到,需求设计的核心不是“把功能列出来”,而是“把系统与外部世界的交互边界讲清楚”。而“系统用例图和用例规约”,是目前为止我在实践里见过最适合干这件事的载体。它可以做到三件事:
- 让业务方用“角色+目标”的视角讲需求,而不是零散地说“我要这个功能、那个按钮”。
- 让开发团队在动手前就明白:系统要为谁服务、每个服务的目标是什么、正常流程和异常流程分别怎么走。
- 让测试人员直接基于用例规约写测试用例,需求和测试天然对齐。
这份《软件需求设计方法学全程实例剖析》系列的第四篇主题,就是系统用例图和用例规约。202601更新版里补充了不少我之前实际项目中用到的经验,包括一些容易画错的边界、规约里容易被忽略的字段。下面我完整展开讲一遍。
需要提前说明的是,这篇文章不是我凭空讲理论,而是围绕一套完整的实例走下来:我们虚构一个“某高校教室预约系统”作为贯穿始终的项目,从画用例图到写用例规约,到最后评审,每一步都给你看实际产出物长什么样。
2. 先弄清用例图的基本构造:要素、关系与符号的准确含义
2.1 四个基本要素,别再用错
用例图本身很简单,就四种东西:参与者(Actor)、用例(Use Case)、系统边界(System Boundary)、关系(Relationship)。但越是简单的东西,越容易用错。我见过太多把参与者画成“数据库”、把用例画成“新增删除修改”的图,那基本就废了。
逐个说一下:
参与者(Actor):是处于系统之外、与系统进行交互的角色。它可以是人,也可以是外部系统,甚至可以是时间触发器等设备。关键判断标准:这个角色的行为是否由系统外部发起,并且它是否直接与系统交换信息。在“某高校教室预约系统”里,参与者至少有:学生(预约教室)、教师(审批或查看预约)、管理员(维护教室信息)、一卡通系统(在签到环节做身份核验),可能还有结算系统(如果涉及缴费)。这些参与者都在系统边界外,但它们都是驱动系统工作的源头。
用例(Use Case):是一组相关场景的集合,完整描述一个参与者使用系统达成某个目标的过程。命名规范通常是一个动词短语:“预约教室”“取消预约”“审批借用申请”。注意,用例描述的是“业务目标”,不是“功能点”。“录入预约表单”不是用例,因为“预约教室”这个目标才是;“保存验证码”更不是用例,那是实现细节。
系统边界(System Boundary):用一个矩形框代表待建设系统本身,用例画在框内,参与者画在框外。边界的作用是明确“哪些东西是我们负责实现的”,防止需求蔓延到外部。很多新手画的用例图没有边界,或者把外部系统的操作也画进来,这是后端开发职责混乱的根源。
关系(Relationship):参与者与用例之间是“关联(Association)”关系,用例与用例之间主要是“包含(Include)”“扩展(Extend)”“泛化(Generalization)”三种关系。后面详细拆。
2.2 三种用例关系,这是新人最懵的地方
包含关系(Include):表示一个用例的执行总是包含另一个用例。例如“预约教室”这个主用例,必然包含“校验可用教室”这个子用例。箭头从基础用例指向被包含的用例,带“《include》”构造型。实际项目里,凡是多个用例都要用的公共流程,抽出来做成包含用例是最佳实践。
扩展关系(Extend):表示在某些条件下,基础用例会插入执行一个可选或例外的用例。箭头从扩展用例指向基础用例,带《extend》。例如“预约教室”在“教室冲突”条件下,会执行“提供冲突提示与备选方案”这个扩展用例。它的典型特征是:去掉它,基础用例依然完整;但它出现时,会在特定扩展点介入。
泛化关系(Generalization):用于参与者或用例之间的继承。比如“教师”可以泛化出“管理员”,“现场登记预约”可以泛化“预约教室”。箭头方向是从子指向父。
这里有一个实操细节我反复强调:不要滥用扩展关系。我见过有些团队把正常流程的每个分支都画成扩展,图上一堆《extend》,阅读性极差。正常逻辑是:只有“可独立存在、但非每次发生”的可选场景,才适合用扩展关系。比如“预约教室”里有个可选的“打印预约回执”,可以用扩展;但如果“校验时间合法性”每次必做,就必须用包含,而不是扩展。
3. 教室预约系统用例图实例:从业务故事到图形表达的完整推导
3.1 先收集原始业务故事,而不是直接画图
很多人拿到需求就直接画用例图,这是错误的顺序。正确做法是:先收集业务故事,也就是用户和系统的交互场景,再从中提炼参与者和用例。
我们模拟的这个“某高校教室预约系统”,业务故事大致有这些:
- 学生想要预约教室,进入系统选择教学楼、时间、座位数,提交预约请求。
- 系统自动检查该教室在这个时间段是否空闲,空闲则生成“待审批”状态的预约单。
- 教师收到预约申请通知,确认安排后审批通过,或者驳回并给出理由。
- 学生在预约开始前,可以取消预约;如果时间已过,不可以取消。
- 系统每天凌晨自动清理过期未确认的预约记录。
- 管理员可以维护教室列表,比如新增教室、修改容量、关闭某层楼的教室进行维修。
- 学生在预约开始前到教室门口,通过一卡通刷卡完成签到,一卡通系统反馈核验结果。
这些故事描述虽然是零散的,但已经覆盖了核心交互。接下来要做的,是划重点。
3.2 提炼参与者和用例:判断“谁”和“做什么”
从故事里,我们能识别出:
- 学生:预约教室、取消预约、查看预约记录、签到。
- 教师:审批预约、查看待审批列表。
- 管理员:维护教室信息、处理过期预约、查询使用统计。
- 一卡通系统:配合签到用例进行身份核验。
- 时钟触发(也可以画成一个参与者或干脆不画,但要在规约里写):自动清理过期预约。
这里有个方法论判断:参与者是按角色划分,不是按具体人划分。同一个物理人可能身兼数职。“某老师也可能是某管理员”,但在他脑子里,参与“审批预约”和“维护教室”是两组不同目标、不同权限体系的交互,所以在用例模型里要拆成两个参与者。
用例的提炼标准就一句:一个用例必须能回答“参与者通过系统达成了什么业务目标”。据此,“选择教学楼和时段”不能算用例,因为达成目标的是“预约教室”。“查看空闲教室”倒是一个用例,因为学生可以在不预约的情况下查看教室情况,这是一个完整的查询类目标。
看,用例图的核心产出,是把“业务故事”转成“角色-目标-交互”的结构化视图。下面是一份可以直接照着画的图面结构:
系统边界内: - 预约教室 (学生 -> 教师,审批状态变化) - 取消预约 (学生) - 查看空闲教室 (学生) - 扫码签到 (学生、一卡通系统) - 审批预约 (教师) - 维护教室信息 (管理员) - 查询使用统计 (管理员) - 自动清理过期预约 (启动定时触发) 关系: - 预约教室 --包含--> 校验教室可用性 - 预约教室 --扩展--> 冲突提示与备选方案 - 扫码签到 --包含--> 一卡通身份核验(通过一卡通系统这个参与者,用《include》关联) - 教师 --泛化--> 管理员3.3 边界怎么定:哪些画进框内,哪些坚决排除
这部分特别关键,也是需求评审会议上撕得比较凶的地方。
“校验教室可用性”要不要作为一个独立用例画在系统里?我的答案是:它在用例图里要体现,但它更合适的方式是“预约教室”用例的包含子用例,而不是单独和参与者建立关联。原因是:外部用户不会单独发起“校验可用性”这个目标,它只是预约流程里的内部步骤。包含用例服务于主用例,不直接面向外部参与者。
“一卡通身份核验”呢?这块要仔细。一卡通系统是外部系统,它本身不在我们系统边界内。我们系统的“扫码签到”用例,在执行过程中要调用一卡通系统来做身份比对。这个核验动作本身不能画成我们系统的一个独立用例,而是应该作为“扫码签到”对“一卡通系统”这个参与者的交互体现。具体到用例规约里面,它是一条步骤加一个外部接口调用说明。如果你把“身份核验”画成系统内部用例,等于把外部系统的职责揽进了自己系统,边界混乱,开发排期也会评估错误。
为什么要这么较真?因为用例图的边界直接决定“你做还是别人做”。一旦边界画错,后续开发、测试、验收全都会乱。需求阶段多画几笔,比开发完再改省十倍成本。
4. 用例规约:把图形背后每一句话落到可执行的细节里
4.1 为什么不画完用例图就够
用例图只是骨架,真正指导开发的是“用例规约”。从实践角度讲,用例规约就是每个用例的说明书,它规定了这个用例的目标、前置条件、主成功场景、扩展场景、业务规则、数据需求等。
我遇到过不止一次:项目组画了二十多个用例图,觉得很完备,结果开发一看规约就傻眼:“你说的‘校验冲突’具体校验什么?提示语写什么?数据从哪来?”没有规约,用例图再漂亮也只是装饰图。
下面用“预约教室”这个核心用例,完整写一份规约样例。这是“某高校教室预约系统”里最复杂的用例,覆盖了大部分常见问题,写明白它,其他用例都可以套同一个模板。
4.2 一个完整的“预约教室”用例规约样例
用例名称:预约教室 参与者: - 主要参与者:学生 - 次要参与者:无(预约阶段不涉及一卡通系统,只涉及内部数据校验;签到阶段才涉及) 前置条件: - 学生已通过系统身份认证,登录会话有效。 - 系统当前处于“可预约”时段(例如教学周第2-18周,工作日 8:00-21:00)。 - 该学生当前没有处于“已预约但未取消”状态的冲突预约(可选约束,按学校制度定)。 后置条件(成功): - 系统为本次预约生成唯一预约单,状态为“待审批”。 - 系统在本条预约对应的教室、时间段上生成占位标记,标记状态为“临时占用”。 - 系统向预约审批教师发送待审批通知。 主成功场景: 1. 学生进入“预约教室”功能页,系统展示本周可选教室列表(含教室名称、位置、容量、多媒体设备信息)。 2. 学生选择教学楼、日期、开始时间、结束时间,输入预约用途(如“课程答疑”),点击“提交预预约”。 3. 系统校验所填时间段在允许预约范围内,且晚于当前时间15分钟以上。 4. 系统调用“校验教室可用性”子流程,排除该教室该时间段已被锁定、已占用、处于维护不可用状态。 5. 校验通过,系统生成预约单,标识状态为“待审批”,同时为教室占用日历添加临时占用标记。 6. 系统显示预约成功页面,展示预约单号、教室、时间段、审批教师姓名,并提示“等待审批结果”。 7. 学生确认并退出功能页。 扩展场景: 3a. 学生选择的开始时间早于当前时间或不足15分钟: 3a1. 系统提示“开始时间必须晚于当前时间15分钟以上”,不创建预约单。 4a. 校验教室可用性发现该时段已被其他预约占用: 4a1. 系统不创建预约单。 4a2. 系统提示“该教室在该时段已被占用”,并展示相邻两小时内空闲教室作为备选建议。 4b. 校验发现该教学楼在所选日期已经被维护关闭: 4b1. 系统提示“该教学楼暂停开放”,不创建预约单。 5a. 预约单创建成功,但发送待审批通知失败: 5a1. 系统不阻断预约成功流程,将通知发送任务放入消息重试队列。 5a2. 系统在预约详情页记录“通知已入重试队列”的内部状态,管理员可后续补发。 业务规则: - 同一学生同一时段最多只能有一条“待审批”或“已审批”状态的预约。 - 教室每个时段容量上限 = 教室座位数 - 2(预留应急座位,具体可配)。 - 预约只能在开始时间前申请;开始后只能取消(且需教师审批取消)。 - 审批通过前,教室临时占用状态对其他学生可见但不可预约。 数据需求(重点字段): - 预约单号:系统生成,唯一,格式 R20260126-001。 - 教室编号:引用教室主数据。 - 预约日期、开始时间、结束时间。 - 预约用途:文本,不超过50字。 - 状态:枚举(待审批、已审批、已驳回、已取消、已完成)。 非功能需求: - 教室可用性校验请求响应时间:小于1秒(内部接口)。 - 当日并发预约请求量级参考:峰值500笔/分钟。 - 预约单数据保留期:3年。4.3 为什么规约里要有“通知失败也走重试队列”
有一个常被忽视的细节:主成功场景第5步里,我特别描述了“发送审批通知失败”时的处理——不阻断预约成功流程,而是把通知任务放进重试队列。
这个场景当年让我们的项目踩过坑。那时候需求方只写了“提交预约后,系统通知审批教师”,开发实现时用了同步调用,结果邮件服务一抖动,学生端整个预约直接报错,数据回滚,学生一脸懵。后来我把这种“非关键路径上的外部依赖失败,不应影响主流程”的规则明确写进了规约里,开发实现时就自然选择了异步消息队列,系统稳定性好了很多。
这就是规约的价值:它不只是抄步骤,而是把异常路径、关键规则、外部依赖边界全部凝固成文字,让开发做技术选型时能直接依据。
5. 容易让人栽跟头的边界案例:扩展、包含与参与者错用场景
5.1 用例粒度的“粗与细”:不是越细越好
画了多年用例图,我发现的规律是:新人容易把用例画得特别碎。“填写预约表单”“选择教学楼”“确认预约信息”“点击提交按钮”全部独立成用例,图上密密麻麻,看起来每一步都“对”,实际上完全没法用。
原因在于:这些其实是“预约教室”这个用例内部的步骤,不是独立的业务目标。用例粒度应该以“参与者能否从这组交互中获得一个可感知的、完整的业务结果”为标准。学生能获得的结果是“预约成功”,所以“预约教室”是一个用例;至于“选择教学楼”,没有人会在系统使用场景里说“我就只想用一下选择教学楼,我还要一个自己的结果”。
反过来也有另一种极端:把粒度拉得过大。“事务申请处理”这种把预约、审批、统计都揉进去的用例,参与者达成什么目标都讲不清,同样不可取。经验值是:一个中等业务系统,用例数量通常在30到60个之间。如果明显超出或低于这个范围,大概率是粒度出了问题。
5.2 参与者到底该画多少:外部系统和时间触发器也是参与者
有些团队画用例图,参与者清一色的人,把外部系统全部忽略。这个习惯很危险。比如我们系统的“一卡通系统”,如果不把它画成参与者,开发可能不知道签到用例还要对接外部接口,排期直接少估三天。测试也可能漏掉“一卡通返回异常时,签到用例该如何处理”的用例。
所以,判断参与者的标准扩展一下:
- 人:学生、教师、管理员等。
- 外部系统:一卡通系统、短信网关、邮件服务、企业微信消息服务等。
- 设备:闸机、自助打印机等。
- 时钟:凡是系统存在“到了某个时间点自动执行”的业务,都可以把定时触发画成一个参与者或标注在用例触发条件里。我们系统里“自动清理过期预约”就属于这类。它不是人发起的,但它的确在系统外部发起了交互,挂着系统边界外是合理的。
5.3 包含和扩展的最容易分不清的实际场景
这里挑一个最典型,也是我评审时反复见到的:把“取消预约”画成“预约教室”的扩展用例。
从字面看,“取消”确实发生在“预约”的流程中,但这完全是两个独立的业务目标:学生一开始要做的是预约,预约成功后他改变了主意,重新发起了一个目标叫“取消预约”。两个用例面向的参与者、前置条件、业务规则都不同,必须平级摆放,而不能用扩展关系。扩展关系要求的“同一个参与者达成的同一目标下,在某些条件下插入执行的额外行为”,取消预约显然不属于这个描述。
判断方法很简单:把两个用例的参与者目标和前置条件写出来对比,如果前置条件、目标完全不同,它们就应该是平级用例,而不是包含/扩展关系。“预约教室”的后置条件是“生成待审批预约”,而“取消预约”的前置条件是“已有至少一条待审批或已审批的预约”。这两个用例天然是两条主线,平级画才准确。
5.4 泛化关系里的继承陷阱
泛化关系用得不多,但一旦用错,影响不小。比如“教师”和“管理员”我并不建议在用例图里画泛化,虽然管理员确实往往也是教师,但他们在系统里的权限模型和交互目标差异很大,把管理员作为教师的子参与者,会让用例图的权限语义变得含糊。更好的做法是:如果管理员确实拥有教师的所有功能外加维护功能,可以画泛化;但如果管理员的审批权限、界面入口都完全不同,还是平级拆开更清晰。
泛化关系适合一种场景:多个用例“共享了完全相同的前置、主流程骨架”,而不是“流程相似”。比如“线上预约教室”和“现场登记预约”如果都要走一个完整预约流程,只是入口、身份核验方式不同,可以把它们作为“预约教室”的两个特殊化用例。这个用法比包含关系更贴近业务语义。
6. 用例规约逐项细讲:从影子字段到验收依据
6.1 为什么“状态机”字段必须写进每个带状态的用例
主场景写完,下一步就是对每一项逐字审视。我的经验是,最容易遗漏的是“状态机”描述。以“预约教室”为例,预约单的状态不是只有“待审批”和“已审批”两种,实际还包括已驳回、已取消、已完成。这些状态和状态流转都应当在业务规则里列清楚,否则开发设计的数据库字典会少好几个枚举值,页面上的状态标签也缺。
给出这个预约单的状态机流转:
状态流转: 1. 学生提交预约 -> 待审批 2. 教师审批通过 -> 已审批 3. 教师审批驳回 -> 已驳回(终态) 4. 学生在开始前取消 -> 已取消(终态) 5. 预约日期已过且状态为已审批 -> 已完成(自动置位,发生在签到或次日零点) 6. 已结束未签到 -> 已完成(预留“未签到”标记字段,供统计分析)这段状态机一旦写进规约,开发建表、测试写用例、前端状态标签控件都不会再出现歧义。这是我在实践里收获最大的一点:不要只写顺畅路径,一定要写完整状态生命周期。
6.2 业务规则里需要单独点名的不变量
“不变量”指的是系统内任何时刻都必须成立的数据关系。这是规约中最能体现“设计功底”的部分。比如:
- 对同一教室的同一时间区间,至多只能存在一条状态为“待审批”或“已审批”的预约记录。
- 若预约状态为“已取消”或“已驳回”,该记录不能恢复为“待审批”。
- 教室临时占用的时间区间,不允许覆盖维护时段。
这些不变量在开发阶段可以翻译成数据库唯一约束、服务层校验逻辑或者乐观锁版本号。如果没有写清楚,大概率会出现“同一时间同一教室被约了两次”的重大生产事故。
6.3 特殊需求、优先级、性能约束单独成段
我在规约模板里习惯加一个“特殊需求栏”,用来放用例相关的容量约束、时间约束、数据保存约束等。针对“预约教室”:
- 并发控制:当两名学生同时请求预约同一教室同一时段时,系统必须只允许一个请求成功,另一个返回“已被占用”。
- 数据删除策略:预约记录不物理删除,只做状态变更。
- 审批时限提醒:待审批超过24小时未处理,系统自动发送一次催办通知。
这些内容也许在需求规格说明书里零星出现,但单独收集进每个用例的规约,会让需求追溯性高得多。每次需求变更,开发就能通过“找用例规约中对应条目”快速定位影响范围。
6.4 规约写完后的验证:用“角色扮演”走查
规约写好后,不要直接发给开发,先做一次“验证走查”。方法是:找一个不在团队里的同事,让他扮演“学生”,另一个人扮演“系统”,拿着序骤清单逐字走一遍,看流程是否通顺,分支是否完整,有没有缺步骤。我们当时就靠这套方法抓出不少漏洞。
比如第一次写“预约教室”主成功场景,写到了第6步“显示预约成功页面”就停了,忘了写“学生确认并退出功能页”的收尾步骤。走查时扮演学生的人问了一句“接下来我还能干嘛”,这才重新补充了后续流程。别小看这些“收尾步骤”,它决定用例完整度,也决定开发是否知道预约成功页面之后要跳转到哪个路由。
7. 从用例规约反推流程:为什么开发要的从来不是用例图
7.1 规约怎么演变成流程图以外的开发输入
用例图本身无法表达“先做什么、后做什么、分支条件和处理人是谁”。这些信息隐含在用例规约的主成功场景和扩展场景里。所以开发不可能单靠用例图写代码,他们还要一张能把业务规则可视化的表达方式,最常见的是“业务流程图”或“活动图”。
我的做法是:在规约确定之后,用“泳道图”或“活动图”把主成功场景和关键扩展场景画出来,一个用例一张图。画法不再用用例关系符号,而是用动作节点、判定节点、泳道来标出不同参与者的职责。例如“预约教室”的流程是:
- 学生动作:提交预约请求。
- 系统动作:校验时间合规性,校验教室冲突。
- 判定:是否通过。若不通过,进入冲突提示分支;
- 通过则系统创建预约单,教室占用标记临时占用。
- 教师动作:收到通知,审批。
- 判定:通过/驳回。
- 通过则状态变更为已审批,否则变为已驳回。
这张图和规约组合起来,开发才能知道逻辑分支到底怎么摆。这个步骤叫“从用例到流程的桥接”,是需求设计里最考验分析师的环节之一。
7.2 什么时候该画流程,什么时候只靠规约
实际项目里,不是所有用例都要画流程图。“取消预约”只有纯状态变更,主场景四条步骤,写清楚规约就完了,画图反而浪费时间。重点项目、高复杂度业务(比如预约审批),画图收益明显。
可以用两个标准判断:
- 用例分支多吗?如果有三个以上的扩展分支,值得画。
- 有多方参与者接力吗?如果跨越学生、系统、教师三方,值得画。
7.3 从规约生成测试用例:需求到测试的零距离
分享一个让团队收益很大的技�巧:把用例规约的“主成功场景”和“扩展场景”直接平铺成测试点,每个场景一条测试用例。效果相当显著。
以“预约教室”为例:
- 测试用例1 - 覆盖主成功场景:合法时间段提交,教室空闲,预约单生成成功,状态为待审批。
- 测试用例2 - 覆盖3a场景:开始时间不足15分钟,系统拦截并给出提示。
- 测试用例3 - 覆盖4a场景:教室冲突,系统提示并提供备选教室。
- 测试用例4 - 覆盖5a场景:审批通知发送失败,预约单仍创建,通知进入重试队列。
- 测试用例5 - 覆盖状态流转:待审批 -> 已审批 -> 已完成。
这样写出来的测试不是拍脑袋,而是需求分析阶段就已经定好的验收依据。开发交付的时候,测试用例和规约会逐条对应,有没有漏需求一眼可见。
8. 一份清晰可复用:用例图与会话规约的评审检查清单
8.1 画图阶段的检查项
这项清单是我在项目里反复用过的,基本上在需求评审会之前,我自己会先过一遍:
- 每个用例是否有明确的参与者?
- 是否所有外部系统都作为参与者画在边界外?
- 是否有用例只表达了“功能点”而不是“业务目标”?
- 用例之间的包含、扩展关系是否正确区分?
- 系统边界是否把外部系统的职责排除在外?
- 每个参与者是否有至少一个用例直接关联?
- 有无把内部步骤(如“填写表单”)误画为独立用例?
- 边界外是否有漏掉的时钟触发、外部系统触发场景?
8.2 规约阶段检查项
- 是否包含前置条件和后置条件(成功态)?
- 主成功场景是否满足“参与者-动作-系统反馈”的完整闭环?
- 是否对每个业务规则都给出了明确描述,而不是“按需求理解处理”这类模糊描述?
- 状态机是否完整,是否覆盖全部终态?
- 是否标记了并发、性能、数据保留等特殊需求?
- 是否描述了外部依赖失败时系统的降级行为?
- 每个扩展场景是否带着编号,能否在测试用例中一一对应?
8.3 评审时的“十分钟有效性验证法”
对于需求评审,我还有一个压箱底的诀窍:拿到一张用例图和一份规约后,不急着逐字读,而是尝试在十分钟内回答三个问题:
- 随便选一个用例,我能说出它的“主要参与者”和“成功后的后置条件”吗?
- 我能讲清楚“系统为谁解决了什么核心业务问题”吗?
- 我能指着用例图,说出哪些是系统自己实现的、哪些必须对接外部系统吗?
如果这三问都答得上来,那么这套用例图和规约就是合格的;如果答不上来,图多半画得虚、规约多半写得空。我在实践中用这个方法淘汰过不少看起来漂亮但实际没用的需求文档。
9. 实操中的另一层经验:用例图和用例规约如何融入团队协作流程
9.1 谁来画、谁来审,千万别只交给一个人
需求分析不是分析师一个人拍板的过程。我在多个项目里验证过:用例图和规约初稿由分析师完成,但评审必须有开发、测试、业务方代表同时在场。开发负责审核“这个需求我能不能实现、实现成本高不高”,测试负责审核“这条规则能不能测出来”,业务方负责审核“这是不是我原本要的业务”,三方缺一不可。
常见的问题是:需求会开得稀松,业务方说自己忙,让“某老师”代句话就完事。结果等开发完交付,业务方一看,说“这不是我要的东西”。到那时返工成本已经是需求阶段的十倍往上。所以评审会一定要让真正使用系统的人坐在现场。
9.2 用例编号与需求追溯,越早建立越轻松
在规约里给每一个用例、场景分支、业务规则都编上稳定编号。比如“RES-U03-S01”代表预约模块第3号用例的主成功场景第1步。建表、写代码时在注释里引用这个编号,测试用例也引用这个编号。这样一来,一旦业务需求变更,只要搜编号就能找到所有受影响的代码和测试。这个习惯初期有点麻烦,但项目规模一大,追溯效率提升得非常明显。我们在中后期维护时,只靠编号串联就完成了三轮需求变更的快速定位,节省了至少三分之一的沟通成本。
9.3 版本管理:202601更新这类版本号意味着什么
本次标题标注了“202601更新”,反映的正是需求文档版本管理的思路。需求文档本身也要走版本迭代,每次业务规则调整、措辞修订、新增用例,都要有一个版本号和一个变更记录。我在实际项目里维护的“用例规约变更记录表”长这样:
| 版本 | 日期 | 修改内容 | 修改人 | 评审人 |
|---|---|---|---|---|
| v1.0 | 2025-12-10 | 初次发布 | 分析师A | B/C/D |
| v1.1 | 2026-01-26 | 新增“审批催办”规则,修订扩展场景4a的备选策略 | 分析师A | B/C |
这个习惯很重要。如果需求文档没有版本记录,两周后团队里根本没人说得清“这条规则是谁在什么时候加的,为什么加的”,改起需求来纯靠猜。
10. 一组高频问题的对照回答
为了便于大家在实际中快速定位问题,我把平时团队里问得最多的问题整理成一张表,每一条都基于真实踩坑经历写处理办法:
| 问题 | 典型表现 | 原因 | 处理办法 |
|---|---|---|---|
| 用例图太碎 | 一个预约功能拆成8个用例 | 把步骤当目标 | 按“业务目标完整性”重新合并 |
| 参与者画错 | 把“数据库”“前端页面”当参与者 | 混淆系统组件与外部角色 | 参与者只能是系统外的人、外部系统、时钟 |
| 扩展滥用 | 所有可选流程全部画成扩展 | 没理解扩展的独立性 | 只有“当前基本流程完整性不受影响”的可选场景才用扩展 |
| 规约没有异常分支 | 只写主流程,开发遇到异常自己猜 | 根本没有收集异常场景 | 业务方、团队一起头脑风暴,至少列出5个异常场景 |
| 前置条件缺失 | 状态机没有初始状态 | 把用例当成孤立流程 | 每次写前置条件时问“什么情况才能进入该用例” |
| 没区分包含与泛化 | 公共流程用泛化表达 | 混淆结构关系 | 公共动作是包含,子类型继承是泛化 |
这张表也基本覆盖了评审会上我见过的大部分问题。对照着检查,能少走很多弯路。
11. 写在最后的项目经验
这套方法不是一蹴而就的。我最初画用例图的时候,也把“新增删除修改”画成一排排用例,被评审老师指出“这画的是数据库操作清单,不是需求”。后来在实际项目里反复打磨,才慢慢掌握从业务故事到参与者、从参与者到用例、从用例到规约的完整推导链。
几个最核心的体会,最后浓缩成几句:
- 用例图不是给机器看的设计蓝图,它是业务方和开发团队之间用来对“系统要做什么”达成共识的沟通语言。画得优雅不如画得准确。
- 用例规约才是真正驱动开发的“第一手需求材料”。用例图告诉你“有几个用例”,规约告诉你“每一个用例到底怎么办”。
- 异常的收集能力,是最能区分需求分析师水平高低的地方。正常流程大家都会写,扩展场景、边界条件、外部依赖失效的处理才体现功力。
- 版本管理从一开始就做。哪怕一个月后你再看自己写的文档,没有版本记录也会懵。
如果要给新手一个最低可行实践路径,我建议:挑一个你日常工作里的真实业务场景,按照上面的方法画出用例图,再用“预约教室”这个样例的规约模板写成完整文档,然后拿给一个不懂该业务的人读一遍,看他读完之后能不能准确描述系统的核心流程。如果能,说明你的用例图和规约已经过关了;如果不能,回头对着检查清单逐条补。这套方法我自己用了很多年,希望对你也有同样的帮助。