谈谈需求的描述-用例(Use Case)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了谈谈需求的描述-用例(Use Case)相关的知识,希望对你有一定的参考价值。

参考技术A

用例(Use Case)是一种描述系统需求的方法。运用用例这种方法来描述系统需求称之为用例建模。用例也是UML规范中的一种标准化的需求表达方式,其中比较有名的RUP(Rational Unified Process)就是以用例来驱动的。

值得一提的是,虽然RUP被认为是一种重量级的软件管理过程,而越来越多的软件开发开始采用敏捷方法来响应瞬息万变的需求变化。但是用例作为一种描述需求的方式,其理念和方法论对我们分析需求还是有一定的帮助。

从表达方式上看,用例相对时序图、流程图等需求表达方式,更加面向对象和面向设计。通常情况下,用例比较容易让没有受过专业培训的人员接受。用例可以作为一种跟用户或者行外人员陈述需求的方式。

用例是一种描述需求的方法,用例描述了在不同的条件下,系统对参与者的请求做出的响应。用例通常通过一个参与者(Actor)( 谁? )向系统做出请求,系统根据参与者的请求( 要做什么? ),在不同的条件下,执行某一行为序列( 系统怎么满足? )。每一个行为序列可以称之为一个场景(Scenario),一个用例包含多个场景。场景也可以称之为用例的一个实例(Instance)。

正式的用例应该包括:用例名、概述、范围、级别、主参与者、项目相关人员和利益、前置条件、最小保证、成功保证、触发事件、主成功场景、扩展场景和相关信息等等。

各个组成部分的意义如下:

用例可以用于不同的目的,如:

不同的编写目的导致了用例在编写过程中有可能出现不同的侧重点。

在不同的团队情况也可能导致用例书写的不一样。比如在一个大型的开发项目组里,就需要严格的按照用例范例进行描述,而在一个小型的沟通频繁的项目组里,则可以采用一种比较简单的描述方式。

上文提到的是比较常见的组成部分。事实上,用例的格式并没有硬性规定,在必要时可以增减里面的信息。具体用例需要包括哪些信息,有不同的流派。有兴趣可以查看相关资料,这里不展开讲。

一句话概括: 你的用例不是我的用例,只有适合的用例才是最好的

本文主要观点均来自于《编写有效用例》(Writing Effective Use Cases )作者是 Alistair Cockburn。有兴趣的可以读一下原著。

用例用于表述需求,但是有两点要注意的:

用例名用于标识一个用例,便于汇总和阅读。

规则:使用主动语态的动宾短语来描述。

一般情况下,建议使用主动语态的动宾短语来描述用例的目标。如: “查找商品” “加入购物车” 。在某些情况下,如需要更准确的表示出一个用例,可以加入定语进行修饰,如: “用户清除购物车” “管理员清除购物车”

规则:以主参与者为对象进行描述。

用例的描述需要以主参与者为对象进行描述,如可以使用 “支付订单” (以主参与者为对象),而不是 “收取订单费用” (以系统为对象)。

用例的范围能让我们对系统的边界和讨论的需求有一个基础的语境,不同的设计范围可能会导致我们需要讨论的参与者、场景都会不一样。简单来讲,就是为我们讨论的系统划定一个范围确定我们讨论的界线。

例如我们要讨论一个用户的下单行为。如果以整个企业为范围,其项目的相关人员为用户、第三方服务者(如快递等)。但如果以系统为范围,其项目相关人员还应该包括企业内部的系统管理员、客服等。

所以,在编写用例时需要搞清楚,我们的用例的范围是什么,这样可以对用例讨论的问题达成一个共识。

在讨论用例的设计范围时,需要先确定系统的功能范围。Cockburn在《编写有效用例》里面推荐了一个确定功能范围的方式 “内/外列表”

确定功能范围的好处是显而易见。如,系统外部已经有了一个打印订单的系统,如果不明确区分系统的功能范围,部分开发人员有可能会对打印订单功能进行设计和实现。而事实上,这些功能是不需要设计的。

明确了功能范围后,还可以确认系统的执行人员。如上面的例子,打印订单系统将作为 “打印订单” 用例的辅助执行者。

设计范围是在功能范围确定了之后做的。设计范围指的是我们在编写用例时讨论问题的边界和对象。我们在用例里面说的范围(Scope)如果没有特殊说明指的就是设计范围(而不是功能范围)。

下面来看一个例子,ECom公司打算做一个ESys的系统,系统里面包括了ESubSys等多个子系统。

如果以ECom为设计范围来讨论用例,我们关心的是用户对公司的需求是什么,公司以什么样的形式满足用户的请求。如果有外部公司,则还要考虑外部公司与公司之间往来的业务是什么。

如果以ESys为设计范围来讨论用例,我们更关心用户向系统发起的请求和系统对请求的响应。同时,如果以ESys做范围的时候,企业内部的员工也成了用例的执行者,我们还应该考虑员工对系统的请求。

确定用例范围,能很好的对其我们要讨论的问题是什么,界定我们讨论问题的范围,给用例一个语言环境。

规则:设计范围是一个简单的专有名称。

用例的范围应该是一个简单的专用名词,简单说明一下用例讨论的范围界线。如,上面的例子中范围可以直接用 “ECom” “ESys” “ESubSys” 来表示。

主执行者是系统相关人员中,请求系统做出响应的人或物。主执行者是对系统请求的发起者,可是 主执行者可以不是直接操作系统的相关人员

其中一种情况下是主执行者通过另一个系统操作相关人员对系统进行操作。如,客户致电客服查询异常订单的场景。客户并没有直接通过系统进行查询。

另一种情况是定时触发任务。如客户希望系统定时执行一个任务,那么最终执行系统的相关人员是系统本身。

虽然识别出主执行者很重要,可是在有些时候 主执行者也没那么重要

在编写用例时,识别出主执行者,可以从执行者角度出发,充分梳理系统需求。我们还可以主执行者的特点来设计系统的交互。如下表,主执行者概括表:

在多数情况下,我们开始编写用例开始后,主执行者就变得没那么重要了。例如,当我们在设计查询订单用例时,无论是管理员、经理、客服甚至是其他的公司职位,在查询订单这个用例上并没有特别的差异。这个时候,主执行者具体是谁已经不重要了。

规则:用例的主执行者可以是执行者或者执行者角色。

在上述情况下,我们会将部分主执行者一般化的方式,创建一个 “角色-执行者对应表” 。在上述用例里,我们将管理员、经理等一般化为一个操作角色——订单管理者。我们在描写用例时,以角色作为主执行者即可。

概述主要用于描述用例的目标,也就是用户需要完成的目标。

规则:使用自然语言描述。

尽量使用自然的语言阐述用户要完成目标时,用户会做什么事情。

规则:描述用例实现什么,而不描述系统步骤。

只需要讲清楚用例需要完成的事情即可,这里不需要描述系统步骤或者用户的具体操作流程。

如: “用户选择一件需要购买的商品后,可以将商品加入购物车,然后在购物车里面提交订单。用户也可以不需要加入购物车,直接购买选中的商品。” 概述并不需要描述具体的系统操作,在这里并没有描述 “点击加入购物车按钮” 等系统的操作细节。

项目的相关人员是指对系统有特定利益的参与者。相关人员不一定是人,也可以是一个外部系统、一个组织等。

所以能成为项目相关人员的有可能是:

主执行者

主执行者是发起执行用例的相关人员。

辅助执行者

辅助执行者是为被设计的系统执行服务的的外部执行人员。辅助执行者可以是另外一个系统、也可以是一个人或组织。如,一台打印机,为系统打印各种票据。再如,快递公司,为系统提供快递服务,并提供物流信息。

内部执行者

内部执行者是在系统内部关注系统利益的相关人员。

被设计的系统

被设计的系统本身有时候对自己也是有特定利益的。

对于相关人员,有几点需要说明:

规则:相关人员和利益用以对应列表的方式书写。

使用" <相关人员>:<利益> "的方式,描写相关人员和其关注的利益。

在编写用例过程中,我们有时会具体描述一个用户的需求(如用户购买商品),有时候会描述一个系统的具体功能(如用户登陆),有时候会描述一个流程(如购买商品并获得商品的流程)。在编写用例的时候,知道用例所处的位置,对我们编写和理解用例有很大的帮助。

我们将用例级别从总到分划分成了三个层次:概要、用户目标、子功能。

用户目标是指主执行者使用系统期望获得的目标。用户目标是我们编写用例的重点。用户目标描述了主执行者通过系统 “做一件什么事” ,以及做完这件事后 “用户能获取什么利益”

用户目标应该是主执行者一次执行系统获取利益的过程。所以,不是一次执行所能完成的目标,或者用户不能获得利益的需求不能称为用户目标。

如,购买一个商品的流程,这个从下订单到快递需要几天的过程,所以不能称为一个用户目标。再如,用户登陆,用户登陆并不能获取什么利益,所以也不能称为一个用户目标。用户下单这个操作,可以作为一个用户目标。

概要层次可以包含多个用户目标,概要目标执行周期比用户目标更长,可以是一个几天、几个月甚至更长的过程。概要目标有三个目的:

子功能层次是用户目标在执行过程中会执行到的目标。如,一次登陆,一次订单打印等。也有可能存在多个用户目标共用一个子功能,如查找商品、查找订单等。

子功能用例的存在是为了用户目标用例增加可读性而存在的。在实际编写过程中, 不到迫不得已,不要设计子功能层出用例

规则:层次只有三个选项:概要、用户目标、子功能。

用例的层次只能是概要、用户目标、子功能三个之中的一个层次。

前置条件是我们在用例执行之前期望必须成功的条件。在用例编写过程中,可以不对该条件进行检查和讨论。如, “下订单” 必须依赖于 “用户已经登陆” 这个前置条件。

规则:前置条件必须是用例执行前我们期望一定成功的条件。

要预防将那些并不是必须条件的条件写入前置条件。如,取消订单并不依赖于用户下单成功,事实上,用户可以将下单不成功(例如支付失败)的订单取消掉。而订单下单是否成功这个条件是需要在用例里面对这个条件进行检查并执行不通过动作的。

最小保证是用例执行无论是否成功都会被执行的保证。虽然,用例无论执行成功与否,最小保证总会被执行。但是,最小保证更多的是为用例执行失败情况下,为用例相关人员提供的利益保证。最小保证可以有多个。

一个常见的最小保证例子是 “系统将用户执行记录日志” ,就算用例执行失败,用户的操作也将会被记录到日志里面。

成功保证是指用例执行成功后,用户所能得到的利益保证。相关人员的利益能否得到保证,是用例执行成功的判定条件。成功保证可以有多个。

例如,在下订单用例中,用户下单成功后,必须保证 “订单被创建,并提交到后台处理。”

触发事件是指用例启动的事件,用例将通过触发事件,开始一步一步执行。

规则:触发事件是跟系统交互的第一个操作。

以用户下单用例为例子,用户决定要购买商品后,在系统中查找商品并下单。那么 “用户决定要购买商品” 并不能作为用例的触发事件,事实上,用户更系统的交互是从 “查找商品” 开始的,所以 “用户查找商品” 才是用例的触发事件。

我们讨论用户跟系统交互时,还应该注意我们讨论的系统的范围。特别是当主执行者不是直接操作软件系统的场景时,更应该明确系统范围。如, “用户致电客户经理下单” 这样的场景下,我们的系统范围并不能限定在软件系统范围内,这是系统范围是公司。所以, “用户致电客户经理” 跟我们系统交互的第一步,所以可以成为 “触发事件”

主成功场景是用例从触发事件开始,一步一步执行,最终满足用例利益的步骤集合。

主成功场景应该包括以下信息:

执行步骤应该有一些简单的规则:

规则:使用简单语法。

使用简单语法结构:

例如:

规则:准确描述执行者之间的切换。

执行步骤需要准确描述步骤执行过程中,执行者之间的切换。如, “用户致电客户代表” ,我们可以知道步骤已经从用户切换到了客户代表。

但是,有时候在执行者明确的情况下,也有可能不会出现在句子中。如, “用户输入密码” ,我们也可以知道这个步骤的执行者已经从用户切换到了系统。我们不必使用 “用户向系统输入密码” 这种冗余的描述方式。

规则:从系统外去描述步骤。

不应该从系统内部,或者全部以系统角度去考虑而已。而应该从系统外去描述步骤。

如果从系统内部去描述步骤,可能会写成:

如果在系统外部去描述步骤,则表述成:

规则:显示过程向前推移。

一些小的步骤只能完成少数工作,有时候这些工作并不能很好的描述过程在向前推移。如, “用户点击了确定按钮” 。这个步骤并不能很好的描述过程在向前推移,用户的真实目的是登陆系统,随着用户登陆系统,用例步骤可以继续往下执行。

规则:显示执行者的意图,而不是动作。

执行者通常是通过操作系统执行一个动作的,在描写用例时,容易将用户动作和执行者的意图搞混。

例如:
1. 系统要求用户输入身份信息
2. 用户输入用户名密码
3. 用户点击确定按钮
4. 系统确认用户身份信息
……

用例过多描述了系统操作界面和用户的动作,如 “要求用户输入身份信息” ,这个并执行者的意图,而只是一个交互动作。

我们可以缩减描述用户动作的步骤,将用例改成:

规则:包含合理的活动集。

描述步骤的时候,并不一定要求每个步骤之包括一个活动。根据需要可以将部分活动集合在一个步骤里面。

如:

这个步骤也可以描述成两个步骤:

用例的描述方式以简单,有效为主,有时候并不拘泥于具体的方式。事实上很多开发团队都形成了自己的用例编写规范。

规则:步骤描述成功的场景,而不要体现可能的失败。

主成功场景的步骤描述的是成功的步骤。例如:

如果这样编写步骤,我们将要继续考虑 “如果判断正确……” “如果判断失败……” 。但是在主成功场景的步骤中,是不体现失败的步骤的。所以,需要将步骤改成

如果如果系统验证失败怎么办?这部分信息放到扩展里面描述。下文会详细说明,这里不展开。

规则:当步骤不连续执行是,可以加入时间限制。

多数情况下,步骤是一步接一步执行的。可在某些时候,可以这样描述:

规则:一个步骤可以涉及多个相关人员。

我们有时候需要通过一个系统向另一个系统发起一个执行动作,可以写成:

规则:可以反复执行一个或多个步骤。

有时用户会反复执行其中一个或多个步骤,这时候需要在步骤中增加一定的描述。如:

扩展是主成功场景的分支,是指主成功场景在一些其他条件下会完成的不同动作。 请注意,使用“扩展”而非“异常”或“错误”,事实上扩展包括了成功和失败两种可能的条件 。其基本的逻辑是,在执行主成功场景时,如果系统……(检测到意外),那么,……(做一些事情)。

常见的有可能出现扩展的场景如下:

在这些场景出现后,我们应该在扩展中描述这些场景处理方式,然后回到主成功场景或者退出用例。

扩展是针对主成功场景的,所以我们写编写扩展的时候,需要用编号来表明扩展的对应关系:

主成功场景如下:

扩展如下:

如果是每个步骤都可能会触发的扩展,可以用”*“号来表示,如:

或者如果是某些步骤触发的共有条件,可以加上步骤来表示,如:

规则:从系统检测到的角度去描述扩展条件。

扩展条件应该是系统能检测到的条件,而不是发生了什么。如,用户忘记密码了,系统不可能检测到用户是否密码或者是其他的什么原因。从系统检测到的角度去描述,系统只能检测到用户输入错误的密码或者用户输入超时。

规则:合理化合并扩展条件。

扩展条件事实上无需枚举出所有的可能出现的场景,和合理的范围内,我们可以将一些扩展条件合并成等价项。判断等价项,有两个标准:

例如,用户输入密码的步骤里面,用户可以忘记密码输入错误,也可以手误输入错误或者其他的可能性,这些条件都是系统不可以检测的条件。首先,将这些条件转换成系统可以测试的条件:密码输入错误。转换后,所有条件就可以合并成一个了。

在来看一下系统可以完成的条件,如,密码输入错误、用户名错误、用户名不存在等,我们系统的处理都是 “提示用户名或密码错误或不存在” 。这时候可以将条件合并成 “系统检测到用户名或密码输入错误”

还有一种情况,如果在低层级(如子功能级别)用例已经完整描述了扩展,那么在其高级别(如用户目标级别)用例,可以不用重复冗余描述。比如,在子功能级别用例 “保存数据” 里面已经完整描述了保存过程中可能出现的各种扩展条件,那么在其上级用例里就可以不用描述了。

--
用例还能以用例图的方式来表示。本文主要是通过用例的关注点和用例的组成来探讨一下一种需求的描述方式,所以就不对用例图召开介绍了。有兴趣的读者可以自行参考其他资料了解。

在敏捷开发越来越受到推崇的今天,用例这种相对较“重”的需求分析和表达模式越来越少的被人使用。当是我们通过研究用例的关注点和分析方式,其很多思想还是可以借鉴到我们日常的需求分析当中的。

用例建模Use Case Modeling

我的工程实践是印章检测项目,属于计算机视觉中的目标检测方向,在对用例建模之前,我先对用例建模进行一些相关的介绍:

1. 用例是什么

我们首先来看一下传统的需求表述方式-"软件需求规约"(Software Requirement Specification)。传统的软件需求规约基本上采用的是功能分解的方式来描述系统功能,在这种表述方式中,系统功能被分解到各个系统功能模块中,我们通过描述细分的系统模块的功能来达到描述整个系统功能的目的。一个典型的软件需求规约可能具有以下形式:

 

技术图片

 

这样的表述实际上已经包含了部分的设计在内。由此常常导致这样的迷惑:系统需求应该详细到何种程度?一个极端就是需求可以详细到概要设计,因为这样的需求表述既包含了外部需求也包含了内部设计。在有些公司的开发流程中,这种需求被称为"内部需求",而对应于用户的原始要求则被称之为"外部需求"。

2 参与者和用例

从用户的角度来看,他们并不想了解系统的内部结构和设计,他们所关心的是系统所能提供的服务,也就是被开发出来的系统将是如何被使用的,这就用例方法的基本思想。用例模型主要由以下模型元素构成:

参与者(Actor) 
参与者是指存在于被定义系统外部并与该系统发生交互的人或其他系统,他们代表的是系统的使用者或使用环境。

用例(Use Case) 
用例用于表示系统所提供的服务,它定义了系统是如何被参与者所使用的,它描述的是参与者为了使用系统所提供的某一完整功能而与系统之间发生的一段对话。

通讯关联(Communication Association) 
通讯关联用于表示参与者和用例之间的对应关系,它表示参与者使用了系统中的哪些服务(用例),或者说系统所提供的服务(用例)是被哪些参与者所使用的。

这大三种模型元素在UML中的表述如下图所示。

技术图片

3 用例的内容

用例图使我们对系统的功能有了一个整体的认知,我们可以知道有哪些参与者会与系统发生交互,每一个参与者需要系统为它提供什么样的服务。用例描述的是参与者与系统之间的对话,但是这个对话的细节并没有在用例图中表述出来,针对每一个用例我们可以用事件流来描述这一对话的细节内容。

4 建立用例模型

使用用例的方法来描述系统的功能需求的过程就是用例建模,用例模型主要包括以下两部分内容:

用例图(Use Case Diagram) 
确定系统中所包含的参与者、用例和两者之间的对应关系,用例图描述的是关于系统功能的一个概述。

用例规约(Use Case Specification) 
针对每一个用例都应该有一个用例规约文档与之相对应,该文档描述用例的细节内容。

在用例建模的过程中,我们建议的步聚是先找出参与者,再根据参与者确定每个参与者相关的用例,最后再细化每一个用例的用例规约。

参与者是由系统的边界所决定的,如果我们所要定义的系统边界仅限于ATM机本身,那么后台服务器就是一个外部的系统,可以抽象为一个参与者。

技术图片

 

值得注意的是,用例建模时不要将一些系统的组成结构作为参与者来进行抽象,

5 确定用例

找到参与者之后,我们就可以根据参与者来确定系统的用例,主要是看各参与者需要系统提供什么样的服务,或者说参与者是如何使用系统的。寻找用例可以从以下问题入手(针对每一个参与者):

  • 参与者为什么要使用该系统?
  • 参与者是否会在系统中创建、修改、删除、访问、存储数据?如果是的话,参与者又是如何来完成这些操作的?
  • 参与者是否会将外部的某些事件通知给该系统?
  • 系统是否会将内部的某些事件通知该参与者?

综合以上所述,目标检测系统的用例图可表示如下,

技术图片

在用例的抽取过程中,必须注意:用例必须是由某一个主角触发而产生的活动,即每个用例至少应该涉及一个主角。如果存在与主角不进行交互的用例,就可以考虑将其并入其他用例;或者是检查该用例相对应的参与者是否被遗漏,如果是,则补上该参与者。反之,每个参与者也必须至少涉及到一个用例,如果发现有不与任何用例相关联的参与者存在,就应该考虑该参与者是如何与系统发生对话的,或者由参与者确定一个新的用例,或者该参与者是一个多余的模型元素,应该将其删除。

可视化建模的主要目的之一就是要增强团队的沟通,用例模型必须是易于理解的。用例建模往往是一个团队开发的过程,系统分析员在建模过程中必须注意参与者和用例的名称应该符合一定的命名约定,这样整个用例模型才能够符合一定的风格。如参与者的名称一般都是名词,用例名称一般都是动宾词组等。

6 用例方法的优点

用例方法完全是站在用户的角度上(从系统的外部)来描述系统的功能的。在用例方法中,我们把被定义系统看作是一个黑箱,我们并不关心系统内部是如何完成它所提供的功能的。用例方法首先描述了被定义系统有哪些外部使用者(抽象成为Actor),这些使用者与被定义系统发生交互;针对每一参与者,用例方法又描述了系统为这些参与者提供了什么样的服务(抽象成为Use Case),或者说系统是如何被这些参与者使用的。所以从用例图中,我们可以得到对于被定义系统的一个总体印象。

与传统的功能分解方式相比,用例方法完全是从外部来定义系统的功能,它把需求与设计完全分离开来。在面向对象的分析设计方法中,用例模型主要用于表述系统的功能性需求,系统的设计主要由对象模型来记录表述。另外,用例定义了系统功能的使用环境与上下文,每一个用例描述的是一个完整的系统服务。用例方法比传统的SRS更易于被用户所理解,它可以作为开发人员和用户之间针对系统需求进行沟通的一个有效手段。

在RUP中,用例被作为整个软件开发流程的基础,很多类型的开发活动都把用例作为一个主要的输入工件(Artifact),如项目管理、分析设计、测试等。根据用例来对目标系统进行测试,可以根据用例中所描述的环境和上下文来完整地测试一个系统服务,可以根据用例的各个场景(Scenario)来设计测试用例,完全地测试用例的各种场景可以保证测试的完备性。

 

以上是关于谈谈需求的描述-用例(Use Case)的主要内容,如果未能解决你的问题,请参考以下文章

用例建模Use Case Modeling

用例建模Use Case Modeling

用例建模Use Case Modeling

用例建模Use Case Modeling

用Use case获取需求的方法是否有什么缺陷,还有什么地方需要改进

用例建模Use Case Modeling