2024-10-0108:27发布于广东人人都是产品经理的官方账号
用例(UseCase)是一种描述需求的方法。运用用例这种方法来描述需求称之为用例建模。用例也是UML规范中的一种标准化的需求表达方式,其中比较有名的RUP(RationalUnifiedProcess,统一软件开发过程)就是以用例来驱动的。
值得一提的是,虽然RUP被认为是一种重量级的软件管理过程,而越来越多的软件开发开始采用敏捷方法来响应瞬息万变的需求变化。但是用例作为一种描述需求的方式,其理念和方法论对我们分析需求还是有一定的帮助。
从表达方式上看,用例相对时序图、流程图等需求表达方式,更加面向对象和面向设计。通常情况下,用例比较容易让没有受过专业培训的人员接受。用例可以作为一种跟用户或者行外人员陈述需求的方式。
用例是一种描述需求的方法,用例描述了在不同的条件下,系统对参与者的请求做出的响应。用例通常通过一个参与者(Actor)(谁?)向系统做出请求(要做什么?),系统根据参与者的请求,在不同的条件下,执行某一行为序列(系统怎么满足?)。每一个行为序列可以称之为一个场景(Scenario),一个用例包含多个场景。场景也可以称之为用例的一个实例(Instance)。
各个组成部分的意义如下:
用例可以用于不同的目的,如:
不同的编写目的导致了用例在编写过程中有可能出现不同的侧重点。
在不同的团队情况也可能导致用例书写的不一样。比如在一个大型的开发项目组里,就需要严格的按照用例范例进行描述,而在一个小型的沟通频繁的项目组里,则可以采用一种比较简单的描述方式。
一句话概括:你的用例不是我的用例,只有适合的用例才是最好的。
用例用于表述需求,但是有两点要注意的:
用例名用于标识一个用例,便于汇总和阅读。
规则:使用主动语态的动宾短语来描述。
一般情况下,建议使用主动语态的动宾短语来描述用例的目标。如:“查找商品”、“加入购物车”。在某些情况下,如需要更准确的表示出一个用例,可以加入定语进行修饰,如:“用户清除购物车”、“管理员清除购物车”。
规则:以主参与者为对象进行描述。
用例的描述需要以主参与者为对象进行描述,如可以使用“支付订单”(以主参与者为对象),而不是“收取订单费用”(以系统为对象)。
【举例】
用例1:购买商品
……
用例的范围能让我们对系统的边界和讨论的需求有一个基础的语境,不同的设计范围可能会导致我们需要讨论的参与者、场景都会不一样。简单来讲,就是为我们讨论的系统划定一个范围确定我们讨论的界线。
所以,在编写用例时需要搞清楚,我们的用例的范围是什么,这样可以对用例讨论的问题达成一个共识。
1)功能范围
在讨论用例的设计范围时,需要先确定系统的功能范围。Cockburn在《编写有效用例》里面推荐了一个确定功能范围的方式“内/外列表”。
确定功能范围的好处是显而易见。如,系统外部已经有了一个打印订单的系统,如果不明确区分系统的功能范围,部分开发人员有可能会对打印订单功能进行设计和实现。而事实上,这些功能是不需要设计的。
明确了功能范围后,还可以确认系统的执行人员。如上面的例子,打印订单系统将作为“打印订单”用例的辅助执行者。
2)设计范围
设计范围是在功能范围确定了之后做的。设计范围指的是我们在编写用例时讨论问题的边界和对象。我们在用例里面说的范围(Scope)如果没有特殊说明指的就是设计范围(而不是功能范围)。
下面来看一个例子,ECom公司打算做一个ESys的系统,系统里面包括了ESubSys等多个子系统。
设计范围的大小
如果以ECom为设计范围来讨论用例,我们关心的是用户对公司的需求是什么,公司以什么样的形式满足用户的请求。如果有外部公司,则还要考虑外部公司与公司之间往来的业务是什么。
如果以ESys为设计范围来讨论用例,我们更关心用户向系统发起的请求和系统对请求的响应。同时,如果以ESys做范围的时候,企业内部的员工也成了用例的执行者,我们还应该考虑员工对系统的请求。
确定用例范围,能很好的对其我们要讨论的问题是什么,界定我们讨论问题的范围,给用例一个语言环境。
规则:设计范围是一个简单的专有名称。
用例的范围应该是一个简单的专用名词,简单说明一下用例讨论的范围界线。如,上面的例子中范围可以直接用“ECom”、“ESys”、“ESubSys”来表示。
范围:电商系统
虽然识别出主执行者很重要,可是在有些时候主执行者也没那么重要。
在编写用例时,识别出主执行者,可以从执行者角度出发,充分梳理系统需求。我们还可以主执行者的特点来设计系统的交互。如下表,主执行者概括表:
在多数情况下,我们开始编写用例开始后,主执行者就变得没那么重要了。例如,当我们在设计查询订单用例时,无论是管理员、经理、客服甚至是其他的公司职位,在查询订单这个用例上并没有特别的差异。这个时候,主执行者具体是谁已经不重要了。
规则:用例的主执行者可以是执行者或者执行者角色。
在上述情况下,我们会将部分主执行者一般化的方式,创建一个“角色-执行者对应表”。在上述用例里,我们将管理员、经理等一般化为一个操作角色——订单管理者。我们在描写用例时,以角色作为主执行者即可。
主执行者:用户
范围:电商系统……
概述主要用于描述用例的目标,也就是用户需要完成的目标。
规则:使用自然语言描述。
尽量使用自然的语言阐述用户要完成目标时,用户会做什么事情。
规则:描述用例实现什么,而不描述系统步骤。
只需要讲清楚用例需要完成的事情即可,这里不需要描述系统步骤或者用户的具体操作流程。
如:“用户选择一件需要购买的商品后,可以将商品加入购物车,然后在购物车里面提交订单。用户也可以不需要加入购物车,直接购买选中的商品。”概述并不需要描述具体的系统操作,在这里并没有描述“点击加入购物车按钮”等系统的操作细节。
概述:用户选中商品后,通过系统下订单购买商品并支付货款。不包括管理员处理订单。范围:电商系统……
1)主执行者
2)辅助执行者
辅助执行者是为被设计的系统执行服务的的外部执行人员。辅助执行者可以是另外一个系统、也可以是一个人或组织。如,一台打印机,为系统打印各种票据。再如,快递公司,为系统提供快递服务,并提供物流信息。
3)内部执行者
4)被设计的系统
被设计的系统本身有时候对自己也是有特定利益的。
概述:用户选中商品后,通过系统下订单购买商品并支付货款。不包括管理员处理订单。范围:电商系统
用户:希望通过系统下订单购买需要他需要的商品。
系统:记录用户购买的订单,以便给订单管理员处理。
在编写用例过程中,我们有时会具体描述一个用户的需求(如用户购买商品),有时候会描述一个系统的具体功能(如用户登陆),有时候会描述一个流程(如购买商品并获得商品的流程)。在编写用例的时候,知道用例所处的位置,对我们编写和理解用例有很大的帮助。
我们将用例级别从总到分划分成了三个层次:概要、用户目标、子功能。
1)用户目标
用户目标是指主执行者使用系统期望获得的目标。用户目标是我们编写用例的重点。用户目标描述了主执行者通过系统“做一件什么事”,以及做完这件事后“用户能获取什么利益”。
用户目标应该是主执行者一次执行系统获取利益的过程。所以,不是一次执行所能完成的目标,或者用户不能获得利益的需求不能称为用户目标。
如,购买一个商品的流程,这个从下订单到快递需要几天的过程,所以不能称为一个用户目标。再如,用户登陆,用户登陆并不能获取什么利益,所以也不能称为一个用户目标。用户下单这个操作,可以作为一个用户目标。
2)概要
概要层次可以包含多个用户目标,概要目标执行周期比用户目标更长,可以是一个几天、几个月甚至更长的过程。概要目标有三个目的:
3)子功能
子功能层次是用户目标在执行过程中会执行到的目标。如,一次登陆,一次订单打印等。也有可能存在多个用户目标共用一个子功能,如查找商品、查找订单等。
子功能用例的存在是为了用户目标用例增加可读性而存在的。在实际编写过程中,不到迫不得已,不要设计子功能层出用例。
规则:层次只有三个选项:概要、用户目标、子功能。
用例的层次只能是概要、用户目标、子功能三个之中的一个层次。
级别:用户目标
前置条件是我们在用例执行之前期望必须成功的条件。在用例编写过程中,可以不对该条件进行检查和讨论。如,“下订单”必须依赖于“用户已经登陆”这个前置条件。
规则:前置条件必须是用例执行前我们期望一定成功的条件。
要预防将那些并不是必须条件的条件写入前置条件。如,取消订单并不依赖于用户下单成功,事实上,用户可以将下单不成功(例如支付失败)的订单取消掉。而订单下单是否成功这个条件是需要在用例里面对这个条件进行检查并执行不通过动作的。
前置条件:用户已经登陆系统。
一个常见的最小保证例子是“系统将用户执行记录日志”,就算用例执行失败,用户的操作也将会被记录到日志里面。
最小保证:系统记录用户操作进度的日志。
例如,在下订单用例中,用户下单成功后,必须保证“订单被创建,并提交到后台处理。”
成功保证:
1.系统成功创建用户订单。
2.系统收到用户支付货款。
3.用户的订单操作和付款信息被记录成日志。
触发事件是指用例启动的事件,用例将通过触发事件,开始一步一步执行。
规则:触发事件是跟系统交互的第一个操作。
以用户下单用例为例子,用户决定要购买商品后,在系统中查找商品并下单。那么“用户决定要购买商品”并不能作为用例的触发事件,事实上,用户更系统的交互是从“查找商品”开始的,所以“用户查找商品”才是用例的触发事件。
我们讨论用户跟系统交互时,还应该注意我们讨论的系统的范围。特别是当主执行者不是直接操作软件系统的场景时,更应该明确系统范围。如,“用户致电客户经理下单”这样的场景下,我们的系统范围并不能限定在软件系统范围内,这是系统范围是公司。所以,“用户致电客户经理”跟我们系统交互的第一步,所以可以成为“触发事件”。
概述:用户选中商品后,通过系统下订单购买商品并支付货款。不包括管理员处理订单。
范围:电商系统
触发事件:用户选中需要购买的物品。
主成功场景是用例从触发事件开始,一步一步执行,最终满足用例利益的步骤集合。
主成功场景应该包括以下信息:
执行步骤应该有一些简单的规则:
规则:使用简单语法。
使用简单语法结构:
主语……谓语动词……前置短语……宾语。
例如:
系统……扣除…一定数量的…用户账户余额。
规则:准确描述执行者之间的切换。
执行步骤需要准确描述步骤执行过程中,执行者之间的切换。如,“用户致电客户代表”,我们可以知道步骤已经从用户切换到了客户代表。
但是,有时候在执行者明确的情况下,也有可能不会出现在句子中。如,“用户输入密码”,我们也可以知道这个步骤的执行者已经从用户切换到了系统。我们不必使用“用户向系统输入密码”这种冗余的描述方式。
规则:从系统外去描述步骤。
不应该从系统内部,或者全部以系统角度去考虑而已。而应该从系统外去描述步骤。
如果从系统内部去描述步骤,可能会写成:
读取用户密码,确认密码正确。
如果在系统外部去描述步骤,则表述成:
用户输入密码。系统确认用户密码正确。
规则:显示过程向前推移。
一些小的步骤只能完成少数工作,有时候这些工作并不能很好的描述过程在向前推移。如,“用户点击了确定按钮”。这个步骤并不能很好的描述过程在向前推移,用户的真实目的是登陆系统,随着用户登陆系统,用例步骤可以继续往下执行。
规则:显示执行者的意图,而不是动作。
执行者通常是通过操作系统执行一个动作的,在描写用例时,容易将用户动作和执行者的意图搞混。
例如:1.系统要求用户输入身份信息2.用户输入用户名密码3.用户点击确定按钮4.系统确认用户身份信息……
用例过多描述了系统操作界面和用户的动作,如“要求用户输入身份信息”,这个并执行者的意图,而只是一个交互动作。
我们可以缩减描述用户动作的步骤,将用例改成:
1.用户输入用户名密码2.系统确认用户身份信息。
规则:包含合理的活动集。
描述步骤的时候,并不一定要求每个步骤之包括一个活动。根据需要可以将部分活动集合在一个步骤里面。
如:
用户下单成功。系统发送短信给用户,告知用户订单号。
这个步骤也可以描述成两个步骤:
用例的描述方式以简单,有效为主,有时候并不拘泥于具体的方式。事实上很多开发团队都形成了自己的用例编写规范。
规则:步骤描述成功的场景,而不要体现可能的失败。
主成功场景的步骤描述的是成功的步骤。例如:
系统判断用户信息是否正确。
如果这样编写步骤,我们将要继续考虑“如果判断正确……”,“如果判断失败……”。但是在主成功场景的步骤中,是不体现失败的步骤的。所以,需要将步骤改成
系统确认用户信息。
如果如果系统验证失败怎么办?这部分信息放到扩展里面描述。下文会详细说明,这里不展开。
多数情况下,步骤是一步接一步执行的。可在某些时候,可以这样描述:
当用户选择直接提交订单时,……。
我们有时候需要通过一个系统向另一个系统发起一个执行动作,可以写成:
用户通过系统向物流系统获取物流数据。
规则:可以反复执行一个或多个步骤。
有时用户会反复执行其中一个或多个步骤,这时候需要在步骤中增加一定的描述。如:
1.用户查找一个商品2.用户将商品加入到购物车中。用户可以重复1~2步,直至用户完成商品选购。3.用户选中购物车中的商品下单……
主成功场景:
1.用户输入需要购买的商品规格和数量。
2.系统确认商品规格和数量。
3.系统显示购买价格。
4.用户完成付款。
5.系统确认收款后,提示用户下单成功。
扩展是主成功场景的分支,是指主成功场景在一些其他条件下会完成的不同动作。请注意,使用“扩展”而非“异常”或“错误”,事实上扩展包括了成功和失败两种可能的条件。其基本的逻辑是,在执行主成功场景时,如果系统……(检测到意外),那么,……(做一些事情)。
常见的有可能出现扩展的场景如下:
在这些场景出现后,我们应该在扩展中描述这些场景处理方式,然后回到主成功场景或者退出用例。
扩展是针对主成功场景的,所以我们写编写扩展的时候,需要用编号来表明扩展的对应关系:
主成功场景如下:
……2系统确认用户密码正确。……
扩展如下:
……2a密码输入错误:……2b密码输入超时:…………
如果是每个步骤都可能会触发的扩展,可以用”*“号来表示,如:
……*用户关闭登陆页面:……
或者如果是某些步骤触发的共有条件,可以加上步骤来表示,如:
……2-5*用户关闭登陆页面:……
规则:从系统检测到的角度去描述扩展条件。
扩展条件应该是系统能检测到的条件,而不是发生了什么。如,用户忘记密码了,系统不可能检测到用户是否密码或者是其他的什么原因。从系统检测到的角度去描述,系统只能检测到用户输入错误的密码或者用户输入超时。
规则:合理化合并扩展条件。
扩展条件事实上无需枚举出所有的可能出现的场景,和合理的范围内,我们可以将一些扩展条件合并成等价项。判断等价项,有两个标准:
例如,用户输入密码的步骤里面,用户可以忘记密码输入错误,也可以手误输入错误或者其他的可能性,这些条件都是系统不可以检测的条件。首先,将这些条件转换成系统可以测试的条件:密码输入错误。转换后,所有条件就可以合并成一个了。
在来看一下系统可以完成的条件,如,密码输入错误、用户名错误、用户名不存在等,我们系统的处理都是“提示用户名或密码错误或不存在”。这时候可以将条件合并成“系统检测到用户名或密码输入错误”。
还有一种情况,如果在低层级(如子功能级别)用例已经完整描述了扩展,那么在其高级别(如用户目标级别)用例,可以不用重复冗余描述。比如,在子功能级别用例“保存数据”里面已经完整描述了保存过程中可能出现的各种扩展条件,那么在其上级用例里就可以不用描述了。
扩展:
2a:数量不足:
2a1:提示用户数量不足,返回步骤1等待用户重新输入。
4a:用户余额不足:
4a1:提示用户余额不足,要求用户更换付款方式。
4a2:用户更换付款方式继续付款。
4b:用户支付密码错误:
4b1:提示用户余额不足,提示用户重新输入密码。
4b2:用户重新输入密码,完成支付。
4b3:用户连续输入3次错误密码,系统冻结用户付款账户12个小时。
更详细的内容可以查看《编写有效用例》(WritingEffectiveUseCases)作者是AlistairCockburn。
本文由@林海舟原创发布于人人都是产品经理,未经许可,禁止转载