什么是用例
用例在UML建模中是最重要的一个元素。正是用例使得其他那些“孤立”的UML元素能够共同组成一篇有意义的文字。因而没有准确的用例定义一切都无从谈起。
然而用例却又是最难以掌握的,除了本身的很多性质难于学习以外,在实践过程中如何使用更是让人摸不着方向。
所谓用例,就是一件事情,要完成这件事情,参与者需要做一系列的活动。而做一件事情可以有很多不同的办法和步骤,也可能会遇到各种各样的意外情况,因此这件事情是由很多不同情况的集合构成的,在UML中称之为用例场景。一个场景就是一个用例的实例。
例如想做一顿饭吃,需要完成煮饭和炒菜两件事情,这两件事情就是两个用例。而煮饭这件事情是可以有不同的做法,可以用电饭煲,也可以用蒸笼做,这就是两种不同的场景,也就是两个实例。而同样是用电饭煲做,如果是糙米,可能要先淘米,再下锅;如果是精米,就可以省掉淘米步骤直接下锅。这就是用例在不同条件下的不同处理场景。
要启动用例是有条件的,要做饭,首先得要有米。这是启动用例的前提,也称为前置条件;用例执行完了,会有一个结果,米变成了饭。这称为后置条件。
综上所述,一个完整的用例定义由参与者、前置条件、场景、后置条件构成。
一个系统的功能性是由一些对系统有愿望的参与者要做的一些事情构成的,事情完成后就达成了参与者的一个愿望,当全部参与者的所有愿望都能够通过用例来达到,那么这个系统就被确定下来了。捕捉功能性需求,就是用例的作用。
用例的特征
用例有着一系列的特征。这些特征保证用例能够正确地捕捉功能性需求,同时这些特征也是判断用例是否准确的依据。
- 用例是相对独立的。不需要与其他用例交互而独立完成参与者的目的。也就是说用例从“功能”上说是完备的。用例本质体现了系统参与者的愿望,不能完整达到参与者愿望的不能称为用例。例如取钱是一个有效的用例,填写取款单却不是。
- 用例的执行结果对参与者来说是可观测的和有意义的。例如,有一个后台进程监控参与者在系统中的操作,不应该作为用例出现;登陆系统是一个有效的用例,但输入密码却不是。
- 这件事必须由一个参与者发起。不存在没有参与者的用例,用例不应该自动启动,也不应该主动启动另一个用例。用例总是由一个参与者发起的,参与者的愿望是这个用例存在的原因。
- 用例必然是以动宾短语形式出现的。
- 一个用例就是一个需求单元、分析单元、设计单元、开发单元、测试单元甚至部署单元。
用例的粒度
在业务建模阶段,用例的粒度以每个用例能够说明一件完整的事情为宜。即一个用例可以描述一项完整的业务流程。这将有助于明确需求范围。
在用例分析阶段,即概念建模阶段,用例的粒度以每个用例能描述一个完整的事件流为宜。可理解为一个用例描述一项完整业务中的一个步骤。这个阶段采用一些面向对象的方法,归纳和抽象出业务用例中的关键概念模型并为之建模。
在系统建模阶段,用例视角是针对计算机的,因此用例的粒度以一个用例能够描述操作者与计算机的一次完整交互为宜。
一般来说,一个系统的业务用例定义在多于10个,少于50个之间,否则就应该考虑一下粒度选择是否合适了。
不论粒度如何选择,必须把握的原则是在同一个需求阶段,所有用例的粒度应该是同一个量级的。另外,粒度选择的问题本质上还是因为边界认定不同而产生的。如果对选择粒度感到困难,或者出现了同一个阶段粒度大小不一的情况,应该首先确认是否选择了一个正确的边界,并时时检查自己是否越过了这个边界。
用例的获得
在准备发现用例之前,确认已经能够清楚理解下面的几个问题:
- 主角(参与者)是位于系统边界之外的
- 主角对系统有着明确的期望和明确的回报要求
- 主角的期望和回报要求在系统边界之内
接下来,可以开始对主角进行访谈,只需要让业务代表从他自己的本职工作出发来谈谈他的期望。可以通过以下问题引导:
- 您对系统有什么期望?
- 您打算在这个系统里做什么事情?
- 您做这件事的目的是什么?
- 您做完这件事希望有一个什么样的结果?
简单地用纸和笔记录下业务代表的访谈结果,从结果中找出用例。
- 应当清楚,主角想做和要做的事情不一定是他真实的目标,也许只是他做事情的一个步骤。比如客户或许会说我首先做……,然后做……,最后做……,需要从冗长的谈话中为客户总结出他的真实目标来;
- 另外,主角对系统的期望也不一定是一个有效的事件,也许真的只是一个愿望,比如客户会说期望界面能漂亮一些,你需要告诉客户他的期望将是一件可以做的事情,而不仅仅是一个主观愿望。
- 不同主角对同一目标可能会有不同的表达,或许就是同一件事情,应当去伪求真,求同存异,而不是简单地就分为两个用例。
- 不同主角的目标可能会相互重叠,呈现出一种交集的状态。应当小心求证,是否这些主角所谈的都只是某个完整目标的一部分?如果这样,应当合并成一个用例,并假定这两个主角在这个用例中只是担任业务工人的角色而不是真正的主角。或者这些主角所谈的是有交叉的部分,但的确是两个不同的目标。如果这样,应当就是两个用例。至于交集部分,需要在概念模型中去提取公共的业务单元。
总之,应道确保:
- 一个明确的有效的目标才是一个用例的来源。
- 一个真实的目标应当完备地表达主角的期望。
- 一个有效的目标应当在系统边界内,由主角发动,并具有明确的后果。
当发现有些业务总是说不清楚,那么应当考虑重新进行访谈。在重新开始访谈以前,你应该考虑调整以下策略:
- 调整系统边界和主角。
- 扩大或缩小系统边界。
- 变更主角。
- 然后,重新开始。
经过几次调整之后,系统边界内应该已经充满了主角的期望,将每一个有效的期望用用例绘制出来,并给一个合适的名字就完成了用例获取的工作。
用例和功能的误区
虽然功能和用例很类似,但是从本质上来说功能和用例是完全不同的。在描述一个事物的时候,可以从以下三个观点出发:
- 这是事物是什么?
- 这个事物能做什么?
- 人们能够用这个事物做什么?
第一种描述是一种结构性观点,即事物的客观存在。但是这个观点不能够说明事物的作用,也就是功能性方面的信息。
第二种描述是一种功能性观点,说明事物可利用的价值。但是这个观点不能够说明事物在某种情形下的真正价值,也就是它缺乏上下文环境,没有人来使用,事物的所有可利用价值可能是无意义的。
第三种面试是一种使用者观点,说明事物对于使用者的意义,以及使用者可以怎么使用它,得到什么样的利益。这种观点不能够说明事物的本质结构,它只是从表面揭示了事物相对与使用者来说是什么,能做什么,可以获得什么。
软件恰恰就是一种还不存在的事物。对于正准备开发的软件,不能从结构观点去描述它,也不能从功能观点去描述它,最好的方法就是从使用者的观点去描述它。
使用者观点告诉需求收集人员,他希望这个系统是什么样,他将怎样使用这个系统,希望获得什么结果。那么软件只需要按照使用者的要求提供一个实现,就不会偏离使用者的预期。至于功能性观点和结构性官观点,则可以通过使用者观点推导出来。
使用者观点实际上就是用例的观点。一个用例是一个参与者如何使用系统,获得什么结果的一个集合,通过分析用例,得出结构性的和功能性的内容,最终实现用例,也就是实现了使用者的观点。
通过上面的分析可以得出这样一些总结:
第一,功能是脱离使用者的愿望而存在。功能用来描述某某东西能做什么,它与使用者的愿望无关,描述的是事物固有的性质。习惯于以功能来看待系统的团队,喜欢从系统的角度出发,说明系统能做什么,而常常系统能做什么并不是使用者关系的。用例是描述使用者愿望的,描述的是使用者对系统的使用要求,用用例来看待系统团队,则是从使用者角度出发,说明使用者将在系统里做什么。
第二,功能是孤立的,给一个输入,通过计算就有一个固定的输出。功能描述是一个个点,如果要达成一个特定的目标,必须要在额外加上一个顺序的过程把点串起来,才能完成一个系统性的工作。而用例描述的是一个系统性的工作,这个系统性的工作非常明确地去达成一个特定的目标。习惯使用功能分解来看待系统的团队,习惯从开发者角度出发,提供大量的功能点。而用用例来看待系统的团队,习惯从客户角度出发,为客户量身定制他们的要求。
第三,如果非要从功能的角度解释用例,那么用例可以解释为一系列完成一个特定目标的“功能”的组合,针对不同的应用场景,这些“功能”体现不同的组合方式。并且,不是先有了这些“功能”才来组合成某个场景,而是先有了场景,才分解出“功能”。在UML种没有功能这个词,实际上从场景分解出来的是对象,这些对象通过消息交互而完成场景。
目标和步骤的误区
一个用例是参与者对目标系统的一个愿望,一个完整的事件。为了完成这个事件需要经由很多步骤,但是这些步骤不能够完整地反映参与者的目标,不能够作为用例。
假设邮局是一个目标系统,作为寄信人这样一个参与者,对邮局有着寄信的愿望。把寄信作为用例是很自然的事情。假设寄信这件事,包括买信封、买邮票、付钱、投递步骤,以完成这个完整事件的步骤作为用例,就会出现这样的笑话:寄信人到邮局付钱。
但是步骤也可以作为用例的。在概念模型阶段,由于需求已经捕获,在对需求进行分析时,实际上已经进入了用例的内部。进入用例的内部意味着边界已经改变,导致参与者也在改变。通常,参与者已经变成了原来的业务工人,自然参与者的完整目的也就改变了。
寄信和收钱,两个用例大小不同,边界不同,参与者也不同,它们显然不应该同时出现在一个视图里。但是现实情况是很多人将不同大小的用例建模在同一个视图里,出现了另一个误区:用例粒度的误区。
用例粒度的误区
产生用例粒度错误的原因首先是分不清目标和步骤。用步骤划分用例会导致不准确的需求获取,以及用例的粒度过于细小。
另一个常常被误用的误区是在同一个需求阶段中的用例粒度大小不一。本质是建模者心目中没有一个清楚的边界,没有时时检查现阶段出于哪个抽象层次而造成的。
业务用例
业务用例(business use case)是用例版型中的一种,专门用于需求阶段的业务建模。业务建模是针对客户业务的模型,通过业务模型可以得到业务范围,帮助需求人员理解客户业务,并在业务层面上和客户达成共识。业务范围不等于需求,软件需求真正的来源是系统范围,也就是系统模型。业务模型是系统模型的最重要输入。
业务用例实现
业务用例实现是用例版型中的一种,专门用于需求阶段的业务建模。一个业务用例的多个业务用例实现都是为了达成同一个目的,但是每个业务用例实现为达成这个目的而采用的方式各不相同。举例说明:“交纳电话费”可以有“营业厅交费”、“银行交费”、“预存话费”三个不同业务用例实现方式。业务用例实现是实现对象追溯到需求的一个重要环节。
概念用例
在UML中没有概念用例的预定版型,但是概念模型用来获取业务模型中的关键概念,分析出业务模型中的核心业务结构以得到一个易于理解的业务框架,还相当重要。实际上业务架构就是在这个阶段产生的。业务架构是业务分析中很重要的一个成果,它对软件架构有着直接的影响。
作为概念模型中的核心元素,概念用例用来获取业务用例中的核心业务逻辑,这些核心业务逻辑揭示了业务模式,成为业务架构的重要指导。同时,概念用例还是从业务用例到系统用例过渡时非常重要的指导。例如:预存话费业务实现,可以从实现过程中获得一些核心业务 开立账户、存入现金、转账、支付划账等。
系统用例
系统用例没有定义版型。系统用例是用例定义系统范围、获取功能性需求的。系统用例是我们得到的最终需求,实际上是划定开发范围,确定系统需求。
用例实现
类似业务用例实现,一个用例实现代表了用例的一种实现方式。