创建用例
用例描述软件在与用户或其它系统交换时的行为。用例本质上就是功能需求的一种形式,描述了谁用它做什么和有什么目的,而不是简单提供一系列特征,行为和实现备注。专注于用例有助你从客户的角度来设计系统。
产生功能需求文档及一系列用例并不少见。举个例子,用例常从用户角度来描述系统,而功能需求描述的是一系列特征和算法的细节。然而,关注这些技术的一种也基本足够。在这种情况下,我建议创建用例,因为这些最能与用户希望与系统交互的方式产生共鸣。当使用这两种方法时,您可以从用例中获得功能性需求,反之也可以,虽然,更典型的是首先同你用户一起产生用例,然后通过用例获得功能需求列表。
提示:用例是从用户的角度来描述需求。
开发用例
每个用例描述了参与者试图完成的目标。参与者指系统外部发起互动的实体,如,人,设备或其它软件。每个参与者在与系统互动中扮演不同角色。举个例子,数据库的单个参与者可能担任管理、开发或数据库其它用户的角色。创建用例描述这种流程的一个好方法是
- 标识出所有参与者和扮演的角色。
- 标识出每个参与者所要完成的目标
- 为每个目标创建用例
每个用例应以朴素的语言和问题域中的术语来编写。每一个用例应该以角色开始,紧接着一个动词。举个例子,下面的例子描述了如何验证用户的PIN码。
- Step 1. 用户插入ATM卡。
- Step 2. 系统验证插入的卡是否合法的ATM卡。
- Step 3. 系统提示用户输入PIN码。
- Step 4. 用户输入PIN码。
- Step 5. 系统检查PIN码是否正确。
用例模板
一个好的用例是一个面向目标的单一行为的描述,包含为完成用例目标的工作流的严格步骤。可以通过提供清晰的前置和后置条件来陈述用例之前和之后的系统状态,即,明确陈述用例之间的依赖及引起用例的触发事件。
用例可以用不同的正式程度和详细记录。例如,它们可以是简单的几句话,或者是结构化,交叉引用必须遵守的特殊模板。甚至可以可视化的方式描述,如用UML用例图。
提示:用例只能是一串简短的面向目标的描述或者是更加正式的,必须遵循规定的模板的结构。
在正式的实例中,会有很多不同的模板格式和风格来描述用例。这些模板是项目的规范,可以是简短或扩展的来适应项目。别浪费时间在模板的细节上:比起遵循死板的符号,清晰地需求的沟通更加重要。
比较常见的模板元素,如下
Name | 用例唯一的名字,经常是动名词格式,如提取现金,购买车票等。 |
Version | 区别用例不同版本的数字。 |
Description | 用一或二句话来简单概述。 |
Goal | 用户想要完成的目标。 |
Actors | 想要完成目标的参与者角色。 |
Stakeholder | 对用例结果感兴趣的个人或组织,如ATM用户和银行。 |
Basic Course | 描述事件的步骤。尽可能避免使用逻辑条件。 |
Extensions | 在一些条件下可以采取的措施。描述了如果目标失败应该做什么,如非法的PIN码输入。 |
Trigger | 引起用例发生的事件。 |
Precondition | 触发成功执行的一串要求。 |
Postcondition | 成功执行之后的系统状态。 |
Notes | 不属于其它类别的额外信息。 |
编写良好的用例
编写用例是个直观的过程。使用朴实的易于阅读的文字来描述软件被如何使用的用户观点。然而,即使是直观的任务,也可以从通用的指导和建议中获得好处。
- 使用域术语:用例应该以客户很自然的术语来描述。这些术语应该是客户熟悉的,并来自于目标域的。实际上,用户应该能够很容易理解和阅读用例,而不需要思考。
- 别过度描述用例:用例应该描述系统的黑盒功能,不应该描述实现细节。如,“使用者用插入钱”来替代“使用者插入1元硬币,然后在插入5毛硬币”。
- 用例不要定义所有需求:用例不包含获取需求的所有可能形式。举个例子,不应该描述系统设计,特征列表,算法,或不是面向用户的系统的其它部分。用例的重点应该在用户如何与系统互动的行为需求描述。
- 用例不要定义设计:从用例中创建高层次的初步设计时,不应该陷入认为用例定义了最佳设计的陷阱。举个例子,不定义性能,安全或网络方面的需求,可能极大地影响特殊的设计。而且用例应该从用户的角度来编写。因此,需要重新解析目标的不精确或冲突的地方,而不是随它们。
- 别在用例中说明设计:人们普遍认为在用例中应该避免描述UI,因为UI是设计,而不是需求,而且因为UI设计是更容易改变。这个原则并没有提到无UI的设计,但是,可以推导出用例不应该保留太多的设计细节。
- 用例可以直接测试:用例本身不是测试计划,因为它们并没有指定详细的输入和输出值。然而,它们指定了用户希望完成的关键工作流。因此,它是直接编写自动化测试的很好的来源。编写一套测试来验证这些关键工作流,将给你自信,确信软件达到了用户的需求,并在将来改进时不会破坏这个功能。
- 预期迭代:别期望在第一次就收集所有用例。用例分析是一个发现的过程;它有助于你更加了解系统。因此把它作为一个迭代的过程,在这个过程中,你可以提取已有的用例,当你扩展整个系统时。然而,需求中的错误将严重影响项目,会导致重新设计和实现。这就是为什么要在用例中避免太多细节的原因之一。
- 别坚持完整的覆盖:与上面一样,不应该预期用例描述系统的所有方面。其实,你也不需要他们覆盖所有方面。系统的某些方面可能很好理解,或不需要用户直接的观点。你也不会有无限的时间和资源来彻底获取用例,应该把重点放在面向用户的目标和工作流上。
下面是一个ATM的完整例子,描述了输入PIN码并使用了模板来描述这个用例。
Name:输入PIN
Version: 1.0
Description: 用户输入PIN验证他的银行账户信息。
Goal:系统验证用户的PIN码。
Stakeholders:
- 用户相应使用ATM服务。
- 银行想要验证用户账号。
Basic Course:
- 系统验证ATM卡是合法的可以在ATM机上使用。
- 系统提示用户输入PIN码。
- 用户输入PIN码。
- 系统检查PIN码是正确的。
Extensions:
a. 系统不能识别ATM卡。
a-1. 系统显示错误信息并放弃操作。
b. 用户输入非法PIN:
b-1. 系统显示错误消息并让用户重试。
Trigger:用户插入ATM卡
Postcondition:用户的PIN码是合法的
需求和敏捷开发
敏捷开发对于软件开发方法而言是通用的术语,与敏捷宣言相匹配的方法。如,XP, Scrum和DSDM。它认为以下质量是有价值的:
- 个人和互动比工具和流程重要
- 工作的软件比综合的文档重要
- 客户的合作比契约协商重要
- 对变化的相应比遵循计划重要
敏捷方法因此不再强调文档为中心的流程,相反喜欢迭代。然而,这并不意味这它们没有任何形式的需求。它只是意味着需求是轻量并很容易变化。维护一个大的,啰嗦的,正式的需求文档不是敏捷。然而,用例的概念仍然是敏捷开发流程很重要的一部分,如Scrum和XP,它们强调用户故事的创建。
用户故事是高层次需求,包含了足够的信息来,让开发人员来估计实现它所需的努力。概念上非常类似用例,除了更短地描述目标,通常是一句话。简短的非正式的用例更类似于用户故事,而不是正式的模板或UML用例。另外一个重要区别是用户故事并不完全完整。很多用户故事随着代码的改进而逐步增加。
提示:用户故事是在敏捷开发流程中捕获最小需求的方法。
另外一个重要方面是,用户故事通常由项目的利益相关者编写,而不是开发人员,即,客户、供应商,业务所有者,或对产品感兴趣的个人。使用户故事简单可以使相关人员可以用较少时间编写。编写用户故事的简单格式:As a 【role】 I want 【something】so that 【benefit】
举个例子,参考刚才的ATM例子,有5个不同的用户故事:
- As a customer I want to withdraw cash so that i can buy things.
- As a customer I want to trasfer money from my saving account to my checking account so I can write checks.
- As a customer I want to deposit money into my accound so I can increase my account balance.
- As a bank business owner I want to customer's identity to be verified securely so that the ATM can protect against fraudulent activities.
- As an ATM operator I want to restock the ATM with money so the ATM will have cash for customers to withdraw.
一组编写良好的用户故事,可以让工程师估计开发的规模,根据提取的抽象数量,如故事点,来实现这些故事。利益相关人员也经常指定用户故事的优先级。然后,定期评估软件状态,如在冲刺阶段或为下一次迭代进一步提供用户故事。
创建好的用户故事,可以使用下面的方法,简写INVEST
- Independent
- Negotiable
- Valuable
- Estimable
- Small
- Testable
另外,前面提到的如何编写用例的建议同样也适用于编写用户故事。