简介: 研发都通常都使用典型场景(scenarios)来理解一个系统的需要是什么和系统是怎样工作的。不幸的是,尽管研发都已这样做了,但他极少用有效的形式归档。用例(Use-Cases)就是将这些场景获取正式化、形式化的技术。 用例是Jacobson在面象对象的软件工程中提出的,但他实际上是独立于面象对象的。用例是获取业务过程和系统需求的有效方式。而且技术本身是非常简单易学的。 使需求可被浏览 形式化场景获取是为了使用户和研发者都能浏览这些场景。所有功能需求符号都必须满足以下两条准则: 应易于需求源和浏览者理解,并且 不应包含系统的形式和内容的所有细节 功能需求是外部需求,用他来评估系统的设计和最终实现。 应当以系统无关的方式获取买家(stakeholders)的需要和期望。 用例令需求可被浏览 用例正被广泛使用。和其他需求分析技术相比,用例已取得成功,这是因为: 用例将系统视为黑盒 用例使了解需求的实现精度变得容易 后者来源于前者。用例应该不涉及需求相关系统的所有内部结构,这样如果用例指出"提交对订单数据库的改动"或"在Web页面显示结果",内部结构显而易见并可标识为潜在的设计限制。 需求不应该涉及所有内部结构是因为:描述内部结构带给设计者额外的限制。没有这些限制设计者会有更大的自由来建立恰当的实现了外部可观察行为的系统,并有可能提供突破性的解决方案。 工业对用例的接受 用例是在大约六年前正式发布的,此后被绝大多数主要对象方法吸收。用例也已被业务处理再工程协会(business process reenginerring community)吸收为描述现有及未来模式业务操作的有效方法。 用例本身最近因其UML中的位置和地位再次得到强调。UML已被OMG接受做为对象系统的标准建模语言。 什么是用例 用例本身是指一个用户或其他系统和要设计的系统进行的一个交互,这个交互是了达到某个目标(goal)。术语活动者(Actor)用来描述有该目标的人或系统。这个术语强调了所有人或系统拥有目标的事实。目标本身是个动词短语,如"客户:下订单","店员:记录库存"。 作为用例的一部分,有必要记录目标成功和失败的对于活动者和系统的含义。在下订单的实例中,目标达成可能包括货物交给活动者和公司收到相应的货款。仔细定义目标成败是定义系统范围(scope)的基础。因为对于一个简易的订单输入系统,目标达成可能仅仅意味着订单已经过验证并且交货已排定日程。 场景中的任务 一个用例中的不同场景显示目标怎样成或败:成功的场景中目标达成,失败的场景中目标没有达成。这里边美妙的地方在于:目标总结了许多的系统使用意图,用户能看见他们被期望臬使用系统。当然系统没有支持他们所有的目标时,用户也能即时察觉而不用等第一个原型研发出来,或甚至糟糕到要等系统全部研发完才发现。 用例应该多大? 一个有趣的话题是试图确定用例的大小。一种方法是将大小和用例的范围和意图联系起来。对于真正大的范围,一个用例不只描述一个独立的系统,而是描述一笔业务用到的所有系统。这种业务用例(business use case)将整个系统当作一个黑盒,并描述活动者和公司相关的目标。业务用例的场景不能对公司的内部结构做所有假设。也就是说:用户应该向公司下订单,不是客户服务部。 而对于系统研发来说,一个用例的范围限制为单个系统。这是用例更常见的形式,称为系统用例(system use case),他们将系统当作黑盒。这些用例不能描述所有内部结构,并且只能使用问题域的语言。 用例的另一个范围是系统内的子系统或构件的设计。这些实现级用例(implementation use case)将构件当作黑盒,活动者是和之有接口的构件。例如:可能用实现级用例说明某个应用程式对所使用的EMAIL构件的需求。 按这样分级,关于用例大小的讨论是容易的。被设计项目(item)的范围界定总的大小(overall size)。为了帮助系统设计者,每个用例应该只描述单一的没有大分枝的活动线索(thread)。违背这一约束,这在不精确或含混的准则中常常能见到,会使得把用例当作测试说明源材料的变得非常难。 作为系统用例的例子,"询问数据库库存是否偏低"就太小了,显然把实现细节和需求混起来了。对比之下,作为系统用例,"管理仓库"就太大了,因为他不可能作为单一的没有大分枝的活动线索来完成,而且从系统看,描述目标成功是非常困难的。但他是个非常好的分部门(parts department)的业务用例。对于分部门来说,定义"管理仓库"目标的成功是可能的(可能用库存清单变化、部门能力或运作成本等术语)。 业务用例的好处在于可用来将其他用例归类。"管理仓库"可用来组合所有和仓库管理相关的用例。 用例的形式化定义 用例是结果的提交者,该结果对特定活动者是可测量的。 正如前面提到的,活动者能是和要设计的系统进行交互的人或外部系统。对于一个用例有能测量的结果的需求,是从单线索需求衍生的。做为可测量结果的一个方面,目标要么成功要么失败,不存在中间结果。(注:如果存在,则需进一步分解细化用例,直到单线索。) 给用例写文件 用例有个非常好的地方,就是能给场景写各种形式化程度文件。每个场景指通过用例的一条独立路径,从某个角度说是一套条件。 能使用非格式化的文本描述,但有多重条件或可能的失败时,跟踪起来有些困难。非格式化的叙述风格在试图理解需求的初始阶段是非常有用的。然而,在接下来的用例研发中,用更形式的机制来写用例文件是非常有用的。 客户的粗略框架(rough sketch):下订单的用例可能是这样的: "识别客户,检查所需的货物在库中并且没有超过他们的信用限制"。 结构叙述(structured narrative)格式能提供更高效的率。这种格式说明一个活动者:目标的序列。这各方式首先写下来的是简单的成功场景,所以的活动者:目标语句都假定前一个目标已成功,这样形成是是最简单的成功场景。 用例认为我们正在设计的系统是个黑盒,根本不记录所有内部结构,并且能看成对写出场景的意图有一个独立的活动者。(and it can be considered to be a single actor for the purposes of writing out the scenario.)用例不描述系统内部的所有情况,只有系统有什么目标和是些什么目标才是用例应当处理的。 —————————- 1. Clerk: Identify Customer 2. system: Identify Item 3. System: Confirm Ship Quantity 4. System: Confirm Credit 5: Customer: Authorize Payment 6. System: Dispatch Order Extensions 1a. Customer not found 1a1. Clerk: Add new Customer 3a. Partial Stock 3a1. Clerk: Negotiate quantity —————————- 处理目标失败-扩展 下一步应该注意的是上面记下来的每一步都可能失败。导致失败的条件能做为场景的扩展来获取。这些扩展的写法是:写下场景在失败条件之后的部份,跟随这部分场景直到回到主体或失败。 分离的失败条件便利场景更具可读性。基本的成功场景是通过用例最简单的路径,路上的每一步中活动者目标都达成了。独立列出所有失败条件能提供更好的质量确保。浏览者非常容易检查是否所有条件都已指明,或更有什么可能的条件被忽略了。失败场景能是可恢复的或不可恢复的。可恢复的场景最终成功了,不可恢复场景直接失败掉。 失败中的失败 另一个需要注意的复杂之处是失败场景可能会再出现其他失败。这意味着扩展区可能有进一步的失败,他能用稍长一些的前缀数字标识:1a1b. Customer is a bad credit risk. 这能在1a1b1中恢复。 为什么用一种结构化的叙述格式? 结构化的叙述体的价值在于他是可辩驳(refutable)的。可辩驳描述的意义在于他足够精确以供争论或赞同: "他不是这样工作的。" "我们在收订单时不检查可用性。" "你丢了一些步骤。" 对比之下,粗略框架提供的非格式化描述则难以辩论,但他对问题域的早期理解是有用的。 另一个可辩驳描述的好处是当你给用例写文件时,希望(expect to)得到用户和研发者的反馈。这是非常有价值的,因为他意味问题在在研发过程的早期就会得到修正。典型的用户反馈是指出不同的顺序、可能的并行性或缺少的步骤。研发者的典型反馈是和说清晰一个特别失败条件的含义及怎么检测他的需求相关的。 用例的图像符号 有用来描述用例的图像符号。在UML中使用一个简单的曲棍球手符号代表活动者,椭圆代表用例,如下图1所示。当你想看看一套用例的相互关系和系统的总图时,这些图可就太棒了。 用例图并不显示不同的场景,他用想显示的是活动者和用例间的关系。因此用例图需要配上结构化叙述的文本。UML有一些图能代替叙述来表示不同的场景,常用的图有交互图和活动图。这些图的主要缺点是是不如文本简洁,但对给出用例的总体感觉是有用的。关于交互图和活动的说明参考"UML Distilled",Martin Fowler(Addison-Wesley 1997)。 获得需求重用 用"活动者:目标"格式写用例描述的价值在于:他将一个用例分解成许多因子(步骤),能将通用的因子变成一个子用例。此后公共部分就能被各个主用例使用了。例如下订单的识别客户这一步就能被许多其他的用例使用。 (注:这也就是UML中常见的用例间泛化关系之一:使用。这里解释的是在需求分析过程中格式化文本能怎么有效的分析出可被其他用例使用的部分。) 应用用例的复杂性和风险 在基本的活动者和用例间没有联系(connection) 有时,在想从用例中获益的活动者和活跃参和用例的活动者之间没有清晰的联系。例如,主办会计(Chief Accountant)可能是"研发票"的活动者,但他们未必会在初始发票运转中活动(actually initiate the invoice run)。这是个问题,用例仍然有效,只不过活动者间的联系是有价值的(getting the value)而用例的初始情况恰好超出了系统设计的范围。基本活动者仍然是有用的,因为扮演该角色的人也就是你写用例文件需要交谈的人。 场景步骤不必序列化 在场景中的顺序步骤无效时,有多种机制能突出可能的并行性。活动图是UML中最佳选择的方法,但非正式的,你能通过查看用例场景,看看那些相同的活动者并在用例中相邻的步骤,来找出并行之处。就在我们前面的例子中,就有并行进行confirm the ship quantity 和 confirm credit的可能性。有时,在用例文件中注意这种可能的并行性是有用处的。 确定用例大小 在开始使用用例是个绝对的风险就是有许多步骤或太少的步骤。如果用例中有多于15个步骤,可能某些实现细节已被包括进去了。如果步骤太少则检查看看目标能通过没有大分枝的独立活动线索而达成。 非常少(如果有)人类活动者 如果非常少人类活动者,多数用例来自其他系统,则用来识别用例的机制应该改动。用和活动者交流(用机器做有点难:-),代替查找系统必须反应或识别的外部事件。 需求分析和系统复杂性 总的看来,场景获取和系统复杂性相关,但即使是大型系统,使用"活动者:目标"对能写出相对简洁的文件。用例格式的价值在于:不同于有大量难以阅读的功能说明,用例令用户和研发者能标识出活动者,然后确认列出的目标符合(或不符合)活动者的工作职责。 但系统并不只是功能需求 用例并不获取系统的所有外部需求。用例非常少获取系统将被怎样使用方面的功能需求。需求更有许多其他方面需要获取并解决。然而一些非功能性的需求是相关的,这样就能将他们附加到一个用例中。一个例子是诸如产量(throughput)和性能(performance)。其他没有使用关联的需求需要分别获取。这种例子可能是: 系统范围 用户对系统所拥有的目标 用户界面原型 通用规则 限制 算法 运行时需求对构造时需求 获取需求时应当记信的一个重要因素是:系统的成员(constituency)比用户团体大得多。系统中有不同主顾,用例只获取其中一部分的需求。本质上,用例只获取系统的运行时需求而忽略了一个主要的主顾:系统研发组织。系统研发组织对说明系统的构造时需求兴趣十足。 运行时需求包括:系统范围、目标和用户组织对产品的期望,用例,其他非功能性需求。 构造时需求包括:易于研发、面对变化时的健壮性、已有构件的重用。 构造时需求能用用例图分别处理,但研发组织还需要解决许多其他方面: 项目范围和目标:什么是项目必须提供的(有别于系统范围,系统范围通常会在多个项目中提供)。 增长和变化的实例:这能作为"变化情况"用通常的用例格式来获取 研发主持约束:这包括标准、实践、工具、质量测量(measure)和质量确认(assurance)的概念和实践 用例的适用性 用例主要针对需要响应外部事件的系统。他们也能用于有明确可理解目标的明显活动者的其他系统。 当外结果示定义或不明确时用例不能使用。 这意味着如果目标成败不能定义,则用例不可用于获取该需求。 应该指出的是,绝大多数现代对象方法都在使用用例,这是因为用例已被证实是需求获取的非常有效的机制。 总结 用例用一种可读、可辩驳的格式获取需求。用例是系统功能性外部需求的可辩驳描述。 可辩驳意指当你给用例写文件时,期望取得用户和研发者关于用例质量的反馈。 用例不必从一开始就精确定义,典型的研发序列如下: 1、识别活动都 2、识别活动者的目标 3、识别每个"活动动:目标"对成败的含义 4、识别这些用例基本的成功场景 5、在细化过程中,识别出失败条件和可恢复/不可恢复场景 只有到决定产品的哪个发布中特定的用例将被研发时才有必要进到第四步。 总的说来,用例是一种有效的需求获取技术,使需求能浏览,避免了需求中的所有实现偏见。