前言
“需求”术语有两种用途,一种用于表达建模得到的结果,另一种用于表达建模的工作流,即需求工作流。文章标题中的“需求”后面有“建模”二字,就是为了强调本文实战的“需求”指的是建模工作流,一般称作需求工作流,简称需求(在没有歧义的情况下)。潘加宇老师的畅销书《软件方法(上):业务建模和需求(第2版)》的书名中的“业务建模”和“需求”指的都是建模工作流。本文的很多理论都出自这本书,通过需求建模实战更深刻的理解和掌握相关技能。
需求描述为了解决组织的问题,系统必须具有的表现——功能和性能。这项技能的意义在于强迫我们从“卖”的角度思考哪些是涉众(Stakeholder)在意的、不能改变的契约,哪些不是,严防“做”污染“卖”。需求工作流主要包括系统用例图和系统用例规约两部分,是本文实战的重点技能。
为了得到需求,需要做的建模工作流包括业务建模和需求。在上一篇文章《业务建模实战》中,我们掌握了业务建模中需要掌握的技能,包括业务用例图和业务序列图。
有了业务建模的铺垫,系统用例图就呼之欲出了。我们将打靶实践案例的业务建模的输出作为需求建模的输入,看看如何从业务序列图映射出系统用例图,还有如何通过用例规约把相关需求表达出来。
系统用例图实战
我们回顾一下该案例的业务序列图:
让我们把思考的边界从组织缩小到要研究的系统,看看什么是系统用例图。所谓系统用例图,就是从用户视角描述系统功能,是用户所能观察到的系统功能的模型图,帮助开发团队以一种可视化的方式理解系统的功能需求。
系统用例图的四要素:
- System(系统):封装了自身的数据和行为,能对外提供服务的整体,用一个矩形块表示;
- Actor(参与者或执行者):在所研究的系统外,与该系统发生功能性交互的人或其他系统,用一个小人表示;
- Use Case(用例):系统外部可见的系统功能,对系统提供的服务进行描述,用一个椭圆表示;
- Relationship(关系):包括执行者与用例之间的关联关系,执行者之间或用例之间的泛化关系,还有用例之间的包含关系和扩展关系,其中关联关系用一个实线箭头表示,泛化关系用一个实线空心三角箭头表示,包含关系用一个虚线箭头+<<include>>表示,扩展关系用一个虚线箭头+<<extend>>表示。
定系统
在业务序列图上可以看出,系统为打靶服务:
找执行者
如果没有做业务建模,识别系统执行者只能靠头脑风暴。现在做了业务建模,直接从业务序列图映射即可。在业务序列图上,将与“打靶服务”有实线相连的对象映射为“打靶服务”的执行者。显然,“靶场管理员、靶子专家和打靶人员”是“打靶服务”的执行者,应放在系统外面。
添用例
用例之前的许多需求方法学,把需求定义为思考系统“做什么”,用例把需求定义提升到思考系统“卖什么”的高度。
在业务序列图中,从外部指向“打靶服务”的消息,可以映射为“打靶服务”的用例,应放在系统里面。
画关系
执行者和用例之间是关联关系。在UML标准中,执行者和用例之间没有要求使用箭头,但笔者认为通过箭头可以明确表示出用例的执行方向,所以建议加上。打靶人员、靶场管理员和靶子专家都是主动发起用例的交互,我们称之为主执行者,箭头是从执行者指向用例。
包含是用例之间的一种关系,其中一个用例(称为基本用例)的行为包含了另一个用例(称为包含用例)的行为,用虚线箭头+<<include>>表示,箭头指向包含用例。
包含关系意味着包含用例是基本用例中不可缺少的一个执行步骤,如果缺少了该包含用例,基本用例就会变得不完整。倘若熟悉面向对象设计与分析方法,可以将包含关系类比为对象之间的组合关系,如汽车与轮胎,是一种 must have 关系。
使用包含关系的两个场景:
- 当基本用例较复杂时,可以分解出一些包含用例
- 当两个或以上的基本用例存在一些重复行为时,可以提炼出一个包含用例
扩展是用例之间的一种关系,其中一个用例(称为扩展用例)的行为增强了另一个用例(称为基本用例)的行为,用虚线箭头+<<extend>>表示,箭头指向基本用例。
扩展用例是对基本用例的一种补充或强化,即使没有该扩展用例,对基本用例也不会产生直接影响,基本用例自身仍然是完整的。倘若熟悉面向对象设计与分析方法,可以将扩展关系类比为对象之间的聚合关系,如汽车与车载音响,是一种 nice to have 关系。
如果一个基本用例还有其他动作,但该动作在一定条件下才执行,可以将它放在扩展用例中。
严格来说,包含用例和扩展用例不能算用例,应该有更好的名字,例如“交互片段”,否则名称中带的“用例”二字容易误导开发人员从实现的角度定义用例,而不是从对外提供价值的角度。
因此,当我们考虑包含用例和扩展用例时一定要谨慎,除非下面几种情况:
- 当基本用例比较复杂时,为了易于理解,会考虑分解出一些包含用例;
- 当两个或以上的基本用例存在一些重复行为时,会考虑提炼出一个包含用例;
- 当有仅在某些特定条件下才会出现的行为时,为了让基本用例保持简洁,而不必将所有可能的场景和变体都直接嵌入到基本用例中,会考虑扩展用例。
通过业务序列图识别的用例属于基本用例。我们发现,“打靶服务”的所有基本用例都有重复登录的行为,考虑提炼一个包含用例为“登录”。所有“打靶服务”用户都可通过“姓名+工号”的方式登录系统,所以“登录”用例依赖公司统一的“用户认证服务”系统。“用户认证服务”虽然也是执行者,但它是在用例的交互中被动参与进来的,我们称之为辅执行者,箭头是从用例指向执行者。
一般来说,辅执行者绝大多数都是外系统,人作为辅执行者的情况比较少,所以碰到辅执行者是人的时候要多留心。除此之外,把信息的接收者或将来可能使用信息的人当成辅执行者也是常见的错误。
系统用例规约实战
用例图表达了用例的目标,但是对于完整的需求来说,这是远远不够的。用例的背后封装了不同级别的相关需求,我们需要通过书写用例规约把这些需求表达出来。用例规约就是以用例为核心来组织需求内容的需求规约。
书写用例规约的模版如下所示:
用例编号:
......
用例名:
......
执行者:
......
前置条件:
......
后置条件:
......
涉众利益:
......
基本路径:
......
扩展路径:
......
字段列表:
......
业务规则:
......
质量需求:
......
设计约束:
......
下面我们以打靶人员进入靶场打靶这个场景为例实战一下用例规约的书写。
用例编号
用例ID,易于理解且唯一就行,比如UC1。
用例名
用例在用例图中已经存在,照搬到用例规约中就可以。
对于打靶靶人员进入靶场打靶这个场景,用例名就是打靶人员→打靶。
执行者
执行者在用例图中已经存在,照搬到用例规约中就可以。
对于打靶用例,执行者有两个:一个是打靶人员(主),另一个是用户认证服务(辅)。
前置后置条件
前置条件是用例开始前,系统需要满足的约束。后置条件是用例成功结束后,系统需要满足的约束。用例相当于系统的一个承诺:在满足前置条件时开始,按照里面的路径步骤走,系统就能到达后置条件。
前置后置条件的约束:
- 前置后置条件必须是系统能检测的;
- 前置后置条件是状态,不是动作;
- 前置后置条件要用核心域词汇描述,两种典型错误:a. “系统正常运行”“网络连接正常”等放之四海而皆准的约束,和所研究系统没有特定关系,不需要在前置条件中写出来,否则会得到一堆没有任何增值作用的废话;b. 后置条件也不能简单地把用例的名字加上“成功”二字变成“××成功”。例如,用例“顾客→下单”的后置条件写“顾客已经成功下单”,这不是废话吗?更合适的后置条件是“订单信息已保存;
- “已登录”不应作为前置条件: 把“登录”作为一个用例,“会员已经登录”作为其他用例的前置条件,这样用例的步骤看起来更清爽,但是严格来说这也是不对的,因为“登录”不是购物网站的用例。如果在做需求时考虑复用,可能已经陷入了设计的思维。能够在多个用例中复用登录的状态,这是设计人员的本事。
对于打靶用例,前置后置条件是什么呢?
- 打靶人员打靶时,需要先登录,然后在靶场列表中查找或搜索目标靶场,接着进入打靶页面开始射击。这就是说,打靶人员打靶前要知道进入哪个靶场打靶,所以前置条件是靶场已新建;
- 打靶人员打靶后,可以查看打靶结果,包括查看成绩和查看答卷两部分(对于练习靶场可以立即查看,对于比赛靶场需要等到比赛结束后才能查看)。这就是说,系统在打靶人员提交答卷后完成了阅卷,并将打靶记录及成绩记录到了数据库,等收到打靶人员查看打靶结果请求时直接从数据库查询打靶记录及成绩来生成响应,所以后置条件是打靶记录及成绩已保存。
涉众利益
前置条件是起点,后置条件是终点,中间的路该怎么走?这就要由涉众利益决定了。
为了寻找用例的涉众,可以用“醉酒法”思考。假设台上的演员“喝醉”(“喝醉”加了引号,是因为在台上的未必是人)了在台上表演,谁看到这个场面会担心自己的直接利益受到侵害?担心的人就是这个用例的涉众。
对于用例“打靶人员→打靶”,这个用例的涉众包括:
- 打靶人员,是打靶服务的人类执行者,担心自己在靶场里没有打靶记录及成绩,或者虽然有打靶记录及成绩,但打靶命中率低;
- 靶子专家,是靶场内容的贡献者,担心靶子质量不高,使得打靶人员没有获得预期的收益,损害了自己的声誉;
- 靶场管理员,是打靶活动的组织者,担心参与活动的打靶人数少,打靶人次少,或平均打靶命中率低。
涉众主要有以下来源:
- 人类执行者,比如打靶人员,是打靶用例的人类执行者;
- 上游,比如靶子专家,是靶子建设的负责人,将建好的靶子提供给靶场;
- 下游,比如靶场管理员,是打靶活动的组织者,负责活动的回顾改进。
基本路径
一个用例会有多个场景,其中有一个场景描述了最成功的情况,执行者和系统的交互非常顺利,一路绿灯直抵用例的后置条件。这个场景称为基本路径。用例把基本路径分离出来先写,目的是凸现用例的核心价值。
用例“打靶人员→打靶”的基本路径如下:
1.打靶人员扫码登录打靶服务;
2.系统反馈靶场列表;
3.打靶人员从靶场列表中查找目标靶场,并进入;
4.系统反馈目标靶场基本信息;
5.打靶人员开始打靶;
6.系统反馈靶子代码及说明文件;
7.打靶人员逐行评审代码,如果发现一个靶点,就选择对应代码块,并根据靶场规范结构化提交一条评审意见;
8.系统保存这条评审意见;
9.打靶人员完成所有靶点的射击后提交答卷;
10.系统根据打靶记录和靶标进行阅卷,保存打靶记录及成绩,并反馈提交答卷成功。
扩展路径
基本路径上的每个步骤都有可能发生意外,其中某些意外是系统要负责处理的,处理意外的路径就是扩展路径。因为一个步骤上出现的意外及其处理可能有多种,所以同一步骤上的扩展路径可能有多条。
对于扩展路径及其步骤的标号,建议采用Cockburn推荐的方法。扩展路径的标号方法是在所扩展步骤的数字序号后面加上字母序号,例如2a表示步骤2的第a条扩展路径,2b表示步骤2的第b条扩展路径。接下来是该扩展路径的步骤,标号方法是在扩展路径编号后面加上数字序号,例如2a1。也就是说,步骤的编号以数字结尾,扩展路径编号以字母结尾。如果有多重扩展,那就继续按此形式标注。
用例“打靶人员→打靶”的扩展路径包括5a、5b和10a,下面分别说明一下:
5a.之前提交过评审意见后未再提交答卷
5a1.打靶人员继续打靶;
5a2.打靶人员选择继承之前未提交答卷的打靶记录;
5a3.返回6。
5b.之前提交过答卷后未再提交评审意见
5b1.打靶人员重新打靶;
5b2.打靶人员选择继承之前刚提交过答卷的打靶记录;
5b3.返回6。
10a.系统阅卷时校验以离线建靶方式上传的靶标文件格式有问题
10a1. 系统反馈提交答卷失败,并说明具体原因;
10a2. 靶子专家修正靶标文件的问题,并重新上传到系统;
10a3. 系统重新阅卷该靶子关联的靶场,并更新靶场所有打靶人员的成绩。
补充约束
路径步骤里描述的需求是不完整的,比如步骤7中的“靶点”包括哪些内容?步骤10中的“打靶记录”又包括哪些内容?系统的性能和设计约束在这些步骤中如何体现?
是时候让补充约束登场了?对,是时候了。
用例规约模版中的字段列表、业务规则、质量需求和设计约束都属于补充约束。补充约束前面的编号不代表顺序,而表示该约束绑定的步骤的编号。补充约束的类型可用类图表示:
说明:有一些补充约束往往不是针对单个用例,而是针对整个系统,可以在所有用例规约的最后,单独用小篇幅描述。
字段列表
字段列表用来描述步骤里某个领域概念的细节。
用例“打靶人员→打靶”的步骤7和步骤10都需要添加字段列表:
7.靶点=文件名+起始行号+结束行号+缺陷大类+缺陷小类+缺陷细项+缺陷备注;
10.打靶记录=打靶人员ID+靶场ID+靶子ID+时间戳+{靶点}。
说明:“{}”表示都个
业务规则
业务规则描述步骤中系统运算的一些规则,比如用例“打靶人员→打靶”的步骤10中的阅卷规则:
- 对于特殊靶点(比如文件名),靶标中靶点的起始行号和结束行号均为0,即不管打靶人员在哪一个代码块提交这个靶点,都能成功命中;
- 对于普通靶点,靶标中靶点的起始行号和结束行号标识的代码块区间,在允许的范围内尽可能的大,以便打靶人员提交的靶点能成功命中。
说明:描述业务规则时要注意的是:业务规则不等于实现算法,它是需求的一种,也是从涉众的视角看“不这样不行”。
质量需求
按传统的需求分类,用例、路径、步骤、字段列表和业务规则可以归属于功能需求。系统满足功能需求,说明系统能把事情做正确。在做正确的基础上,系统还需要在做的过程中满足一些指标,这些指标就是质量需求(非功能性需求)。质量需求包括可用性、性能(速度、容量和能力等)、可靠性(系统的安全性和完整性)和可支持性(系统升级和修复的能力)。
关于用例“打靶人员→打靶”的质量需求,我们以性能为例进行说明:
- 系统在3秒内完成打靶页面的响应;
- 系统每秒允许最多500个打靶人员同时打靶。
设计约束
设计约束是在实现系统时必须要遵守的一些约束,包括界面样式、报表格式、平台、语言等。设计约束既不是功能需求,也不是质量需求。
关于用例“打靶人员→打靶”的设计约束:
- 打靶人员打靶时,界面要考虑缺陷助手,方便系统根据用户关键字模糊匹配缺陷分类;
- 打靶命中率需要拆分为两个子指标:靶标命中率(命中靶点数/靶标靶点数)和射击命中率(命中靶点数/射击靶点数)。
完整的用例规约
用例编号:
UC1
用例名:
打靶人员→打靶
执行者:
打靶人员(主)、用户认证服务(辅)
前置条件:
靶场已新建
后置条件:
打靶记录及成绩已保存
涉众利益:
1.打靶人员——担心自己在靶场里没有打靶记录及成绩,或者虽然有打靶记录及成绩,但打靶命中率低;
2.靶子专家——担心靶子质量不高,使得打靶人员没有获得预期的收益,损害了自己的声誉;
3.靶场管理员——担心参与活动的打靶人数少,打靶人次少,或平均打靶命中率低。
基本路径:
1.打靶人员扫码登录打靶服务;
2.系统反馈靶场列表;
3.打靶人员从靶场列表中查找目标靶场,并进入;
4.系统反馈目标靶场基本信息;
5.打靶人员开始打靶;
6.系统反馈靶子代码及说明文件;
7.打靶人员逐行评审代码,如果发现一个靶点,就选择对应代码块,并根据靶场规范结构化提交一条评审意见;
8.系统保存这条评审意见;
9.打靶人员完成所有靶点的射击后提交答卷;
10.系统根据打靶记录和靶标进行阅卷,保存打靶记录及成绩,并反馈提交答卷成功。
扩展路径:
5a.之前提交过评审意见后未再提交答卷
5a1.打靶人员继续打靶;
5a2.打靶人员选择继承之前未提交答卷的打靶记录;
5a3.返回6。
5b.之前提交过答卷后未再提交评审意见
5b1.打靶人员重新打靶;
5b2.打靶人员选择继承之前刚提交过答卷的打靶记录;
5b3.返回6。
10a.系统阅卷时校验以离线建靶方式上传的靶标文件格式有问题
10a1. 系统反馈提交答卷失败,并说明具体原因;
10a2. 靶子专家修正靶标文件的问题,并重新上传到系统;
10a3. 系统重新阅卷该靶子关联的靶场,并更新靶场所有打靶人员的成绩。
字段列表:
7.靶点=文件名+起始行号+结束行号+缺陷大类+缺陷小类+缺陷细项+缺陷备注;
10.打靶记录=打靶人员ID+靶场ID+靶子ID+时间戳+{靶点}。
业务规则:
1.对于特殊靶点(比如文件名),靶标中靶点的起始行号和结束行号均为0,即不管打靶人员在哪一个代码块提交这个靶点,都能成功命中;
2.对于普通靶点,靶标中靶点的起始行号和结束行号标识的代码块区间,在允许的范围内尽可能的大,以便打靶人员提交的靶点能成功命中。
质量需求:
1.性能方面:
1.1系统在3秒内完成打靶页面的响应;
1.2系统每秒允许最多500个打靶人员同时打靶。
设计约束:
1.打靶人员打靶时,界面要考虑缺陷助手,方便系统根据用户关键字模糊匹配缺陷分类;
2.打靶命中率需要拆分为两个子指标:靶标命中率(命中靶点数/靶标靶点数)和射击命中率(命中靶点数/射击靶点数)。
小结
要达到“低成本制造好卖的系统”的目标,并非喊喊口号就可以,需要静下心来学习和实践业务建模和需求,希望本文对你有一定的启发。
最后感谢一下潘加宇老师,他把多年的思考、探索、理解通过大白话和可以实践的工作流真诚地传授给我们,带领我们走出了软件建模的混沌状态,让软件建模变得清晰和精准。