引言
作为 BU(UML 出现之前)时代面向对象技术的追随者和支持者,我必须承认当时的业内思想领袖所传播的各种方法和表示法对我具有某种魔力。在 UML 出现之前的两到四年中,您可以走进一个挤满 OO 鼓吹者的房间,并提问以下问题:
我认为这种 OO 技术很有前途,但是告诉我,既然对象共享行为和数据,那么您如何称呼对象为实现它的行为义务而做的事情呢?
您可能得到如下答案:
- “它是一个职责!”(Wirfs-Brock)
- “它是一项操作”(Booch)
- “它是一项服务”(Coad/Yourdon)
- “它是一个(虚)函数”(Stourstrup)
- “它是一个方法”(其他很多人)
如果这还不足以让您混淆的话,那么就不要问您如何用图形表示我们称之为对象和类的东西了。(它是一个矩形、一片云,等等。)虽然这看上去很愚蠢,但是实际情况是,我们软件工程领袖的其中一些最显著的共识(继承、关系、封装),由于在术语和表示法上的微小区别而无法得到共享,或者至少变得混乱。换言之,不管是 OO 工程科学还是将要获得的利益都不能继续向前发展,因为还没有发明用来描述该科学的语言。当然,要在这些作者、方法学家 和独立思想者中达成共识不是一件小事情,但是最终UML面世了,软件工程科学又向前迈进了一大步。
虽然需求管理方法学可能不像 UML 出现之前的 OO 方法学所形成的巴比塔那样糟,但是它却经历了同样的一些问题–尤其是对常见词汇的模糊、不一致和过度使用非常盛行。这些词汇(包括诸如”用例”、”特性”和”需求”这样的基本概念)是”每个人都理解”的日常词汇,但是在给定的上下文中每个人又赋予了它们自己的含义。结果就是沟通不畅。这种情况仅在将达成共识作为成功标准的领域中发生。Booch [Booch 1994]引用了 Stepp 的说法:
科学中普遍存在的一个问题是为观察到的对象和情形构造有意义的分类。这样的分类能推动人们对观察以及后续的科学理论开发的理解。
为了推动需求的”科学理论”,我们不得不面对术语的问题。
本文的目的在于,通过定义并描述用于说明系统软件需求的一些最常见术语和概念,来初步探讨一下软件工程的原理。为此,我们希望提供一个能让所有涉众(用户、经理、开发人员等)达成共识的基础。当然如果我们更有效地交流并因此获得一致看法,那么就可能更快地开发并交付更高质量的系统。
本文重点不在于需求管理的原理–关于这方面笔者在建议读物中推荐了很多参考书目。本文的目的仅是帮助该领域中的从业者提高他们对系统正确行为的基本认识。
问题域与解决方案域的对比
在开始描述具体的术语之前,我们首先要意识到需要从两个完全不同的方面定义术语:问题方面和解决方案方面。我们分别称之为问题域和解决方案域。
问题域
如果我们在问题域上做一次”低空滑翔”,就会发现许多实际生活周围的事物。比如”滑翔”过人力资源部门时,会看到雇员、负责发工资的职员以及工资支票。”滑翔”过重型设备工厂时,我们会看到焊工、焊接控制器、焊接机器人和电极。”滑翔”过万维网时,我们会看到路由器和服务器群集,以及具有浏览器、电话机和调制解调器的用户。换句话说,在任何问题域中,我们可以轻易地识别出我们看到和接触到的事物(实体)。有时候,我们甚至可以看到这些事物之间的关系;比如,web 用户和浏览器之间就是一对一的关系。我们可能还会看到从一个事物传递到另一个事物的消息:”焊接工似乎正在往焊接机器人的’大脑’中编制工作次序”。
如果我们是敏锐的观察者,可能会发现亟待解决的问题:”焊接工对不能安排正确的工作次序感到气馁”或者”注意到雇员输入薪水数据与收到支票之间有令人不愉快的时间延迟!”。有些问题似乎只是在乞求一种解决方案。也许我们可以构建一个系统(更好的可编程控制器、更有效的工资处理)以帮助那些可怜的用户解决这些问题。
基于用户和涉众需求
然而在我们构建新系统之前,我们需要确保理解了该问题域内用户的真正需要。如果没有,我们可能会发现焊接工只能愁眉苦脸,因为他就好像脚上得了鸡眼一样痛苦,结果就是他和他的经理都不会对购买我们最新的”SmartBot”自动焊接控制单元感兴趣。我们还注意到当我们试图销售 SmartBot 时,经理是购买决策中的关键涉众。我们不记得在”滑翔”中看见过她。(也许她当时正在吸烟室,而那里正是我们摄像头的盲区)。换言之,不是所有的涉众都是用户,并且如果我们希望有机会卖出SmartBot,则我们必须同时理解两个社区(涉众和用户)的需要。为了简便起见,我们称所有这些需要为涉众需求,但是我们要不断地提醒自己系统的潜在用户有时代表了很重要的一种涉众类型。
我们将涉众需要定义为:
业务、个人或操作问题(或机会)的一种反映,其中这些问题必须得到解决,以使用户相信他们考虑、购买或使用新系统的选择是正确的。
于是涉众需求就成为与问题域关联问题的一种表示。这些涉众需求并未给出解决方案,但是以一个最初的角度,使我们了解需要实现哪些可行的解决方案。比如,如果我们会见重型设备制造厂中管理焊接工的经理,就可能发现焊接大量重复性的焊接件会消耗巨大的制造时间和成本。另外,焊接工似乎不会喜欢这些具体工作,因为他们一直处在被烫伤的危险中。更糟的是,该工作的物理方面(重复、难以琢磨的手工操作位置以及对视力的危害等)带来了个人安全问题以及长远的健康隐患。
充分理解了这些事项,我们就可以开始定义其中一些涉众需求:
- 我们需要一种自动化的方法来制造大量重复的焊接件,而不用让焊接工手动控制电极。
- 我们很乐意能有一位焊接工,但是我们需要将其移到焊接件以外的安全区域并且远离那些移动的机器。
- 我们需要能轻松使用”训练模式”,这样一般的焊接工也能够”训练”机器为他们做大部分工作。
- 我们需要使训练模式中具有更大的灵活性,并且意识到这可能与用户友好性需要的某些方面产生冲突。
当理解了系统的这些不同方面后,主观上我们会将这些发现”堆放”在一个称之为涉众需求的小堆中。
解决方案域
幸运的是,对问题域的”滑翔”不会花很长时间,并且(通常)我们在问题域中发现的东西也不是很复杂。当我们完成”滑翔”并开始构建我们观察到的问题和需要的解决方案时,就开始理解问题。是的,我们已经开始了最难的一部分:构建问题的解决方案。我们考虑活动集(系统定义、设计等)、为了解决问题而发现和构建的”事物”(计算机、机械臂等),以及在解决方案域的处理部分中创建的工件(比如源代码、用例和测试)。
在解决方案域中,我们必须成功地执行很多步骤和活动,这样才能定义、构建并最终部署问题的成功解决方案。它们包括:
1) 理解用户需求
2) 定义系统
3) 管理范围并管理变更
4) 精化系统定义
5) 构建正确的系统
简言之,上述步骤定义了需求管理的一个简化过程。本文不打算详细介绍这些步骤;关于这些内容我们会为您推荐一些参考读物,包括课本”Managing Software Requirements”,[Leffingwell, 1999]。本文与该参考书保持一致,这里提供的大部分定义都来自该参考书。
比如,在参考书[Leffingwell, 1999]中,我们会发现需求管理是这样定义的:
获取、组织和记录系统需求的系统化方法,在客户与项目团队之间建立并维护对系统需求变更的一致意见的过程。
还是让我们继续寻找并定义用于描述待建系统所需的其他更多的需求管理术语吧。
解决方案域中的常见需求术语
产品或系统的特性
当我们开始考虑已识别问题的解决方案时,很自然会匆匆记下系统的特性。特性在系统的开发中占有很有趣的地位。它们看上去介于用户真正需要的表达与系统实现这些需要的详细方式描述之间。这样,它们就为按照抽象的方式描述系统提供了一种方便的构造,或者如果您愿意的话,提供一种”速记方法”。由于需要解决的问题存在很多可能的解决方案,所以在某种意义上特性提供了特定系统解决方案的最初范围;它们描述了系统打算做什么以及不打算做什么。
我们将特性定义为
系统为实现一个或多个涉众需要而提供的服务。
我们可以很容易地使用用户熟悉的术语用自然语言来表示特性。例如:
- 系统使用的是标准的北美电源。
- 树浏览器提供了组织缺陷信息的一种手段。
- 家用照明控制系统具有与标准家用自动化系统的接口。
由于特性是从涉众需求派生而来的,所以我们将它们安排在金字塔的下一层,即需要的下面。与此同时,我们还从问题域(需要)转移到了解决方案域的第一层(特性)。
有一点很重要,需要注意,那就是特性不仅仅是涉众需求的精化(增加了细节)。相反,它们是用户提供的对问题的直接响应,并且它们为我们提供了问题的顶级解决方案。
通常,我们应该能够通过定义 25 到 50 种刻画系统行为的特性来描述系统。如果您发现手头有超过 50 种的特性,那么可能是因为您没能抽象出系统的真正特性或者是系统过于庞大而难于理解,您需要考虑将其分为更小的部分。
特性是用自然语言描述的,所以读到该清单的任何涉众都能立即获得对系统行为的基本理解。特性清单会缺乏细粒度的详细程度。这没关系。我们只是在试着交流目的,并且由于很多涉众都是非技术人员,所以过多的细节可能会让他们混淆甚至干扰理解。通过例子,我们 SmartBot 自动焊接机器人的部分特性清单可能包括:
- 允许焊接工教导机器人焊接哪些路径的”lead through path”训练模式
- 支持重复焊接次序的”step-and-repeat”特性。
用例
当我们进一步考虑系统完成用户任务的方法时,我们可能发现使用用例技术来进一步描述系统行为很有利益。该技术在很多书籍[Jacobson 1992]中已经得到了很好的发展,并且也是行业标准统一建模语言[Booch 1999]的一个组成技术。
从技术上说,用例:
描述了系统执行的、为用户带来价值的一系列动作。
换言之,用例描述了有助于用户实现他们期望的一系列用户和系统交互。再换一种说法,用例描述了用户和系统如何共同合作以实现所识别的特性。
用例还引进了参与者这项构造。参与者只是当时使用系统的用户的一个标签。在 UML 中,用一个简单的椭圆来表示用例,而参与者则用一个带有名称的线条画表示。所以可以如下所示用一个简单的图来说明这两者。
用例技术规定了参与者如何实现用例的一个简单的逐步过程。比如,用于 Step and Repeat 的用例可能如下所示:
步骤1:焊接工按下 step and repeat 按钮,启动该序列。
步骤2:焊接系统为驱动电动机供给电源,以便可以人工控制机器臂移动。
步骤3:焊接工握着扳机,将机器臂移动到焊接部位,并按下”weld here”按钮,焊接每一条需要焊接的线路。
用例技术提供了很多其他有用的构造,比如预描述和后描述(pre and post description)、可选流(alternate flow)等。我们将在后面详细讨论用例时再讨论它们。但是现在,我们只需要知道用例提供了一个优秀的方法用来描述如何实现系统特性。
出于计划的目的,可能需要除用例之外的一些方法来描述如何实现特定的特性。对于每个特性可能只需要几个用例即可(也许 3 到 10 个)。在描述用例过程中,我们详细阐述了系统的行为。随着其他特征的获得,用例也变得更加详细。
远景文档
在很多开发尝试中,问题的声明、关键涉众、用户需求、系统特性清单,也许还有示例用例都可以在一个被称为远景文档的文档中找到。它还有其他很多名称,比如项目章程(Project Charter)、产品需求文档(Product Requirements Document)、市场需求文档(Marketing Requirements Document)等。不管名称如何,远景文档强调了正在构建系统的总体意图和目的,因此,是那些被标明日期的特性和说明性用例的自然容器。换言之,远景文档捕获了系统的完全形态,并使用涉众需求、特性和用例来交流意图。
然而,我们不能简单地把这些特性和初始用例转交到开发团队手中,并期望他们很快开发出真正满足涉众需要的系统。我们可能需要在系统功能方面更加明确,并且可能涉及了各种新的涉众,包括开发人员、测试人员等。这是系统定义的下一层(软件需求)要解决的需要。
软件需求
软件需求在软件定义过程中提供了下一层特异性。在这一层上,我们必须指定足够的需求和用例,以便开发人员可以编写代码,并且测试人员可以测试这些代码是否满足需求。从图形上说,软件需求提供了我们金字塔的塔基。
什么是软件需求?尽管在过去的多年中已经有过很多种定义,但是我们发现需求工程创始人 Dorfman 和 Thayer[Dorfmann 1990]提供的定义最合适:
- 用户解决将实现一个目标的问题所需的软件功能,或者
- 必须被一个系统或者系统组件满足或拥有,以满足合同、标准、规范或其他正式发布文档的软件功能。
应用该定义,开发团队能够开发出更具体的需求集,以完善或精化前面讨论过的特性清单。每个需求都是某种特性,反之亦然。注意这种方法的简单性。我们有一个特性清单,然后通过编写一个为这些特性服务的需求集来精化它们。我们不编写任何其他需求。这避免了只是坐在椅子上、瞪着天花板,并”为该系统捏造一些需求”的诱惑。
该过程简单明了,但是并不容易。每个特性都需要检查,然后编写需求以支持该特性。不可避免地,为某项特性编写需求会引发您为已经检查过的特性添加新的需求,或者对其进行修订。
当然,您知道编写需求并不容易,并且可能需要指定大量需求。我们发现考虑三种类型或者种类的软件需求(功能性需求、非功能性需求和设计约束)很有帮助。
我们发现这三种需求在我们考虑需求的方式以及我们期望需求实现的任务方面很有帮助。让我们看一下这些不同类型的需求,以及您可以如何使用它们来定义期望系统的各个方面。
功能性需求
功能需求表达了系统行为。更具体地说,功能需求描述了输入和输出分别是什么、以及特定输入如何在不同时刻被转化成特定的输出。能有效工作的大部分软件应用程序都具有丰富的功能性需求。在指定这些需求时,要权衡模糊性(”当您按下 On 钮之后,系统就会打开”)与具体性这二者的关系,这一点很重要。给予设计人员和实现人员以尽可能多的设计和实现选择也很重要。如果我们过于具体,那么就可能过于限制开发团队,如果过于宽松,则开发团队就不知道系统应该实现哪些功能。
指定需求的正确方法不只一种。其中一种技术只简单采用了声明性的方法,并写下系统需要做的每一件详细的事件。
比如: 在”weld here”输入被激活时,系统通过每 100 毫秒读取一次光编码器来数字化电极端的位置。
细化用例
在很多系统中,通过精化以前定义的用例并开发其他用例,则易于组织规范活动来全面细化系统。利用这项技术,您可以将用例步骤精化成更详细的系统交互。您还需要定义前置条件和后置条件(在用例之前和之后陈述系统假设),以及由于异常条件而需要的备用动作等。
由于用例在语义上是良好结构的,因此它们提供了一种组织和捕获系统行为的结构。下面是 Smartbot 的代表性用例。
非功能性需求
除了像输入转换为输出这样的功能性需求,大多数系统还需要定义一组着重指定其他系统”属性”的非功能性需求,比如性能需求、吞吐量、可用性、可靠性和可支持性。这些需求和面向输入输出的功能需求同样重要。通常,非功能性需求的表达方式是声明性的,如: “系统的平均故障间隔时间应该为 2000 小时”,”系统的平均修复时间应为 0.5 小时”,以及”Smartbot 最多应该能够存储和检索 100 条焊接路径”。
设计约束
与定义系统行为不同,第三类需求通常对系统设计或者我们用来构建系统的过程施加了限制。我们将设计约束定义为:
系统设计上的限制,或者系统开发步骤上的限制,它不影响系统的外部行为,但是必须被实现,以满足技术、业务或合同要求。
典型的设计约束可能是这样表达的:”用 Java 为焊接工控制单元编程”。一般来说,我们将合理的设计约束看作其他需求,尽管符合这些限制的测试可能需要不同的技术。正如功能性和非功能性需求一样,这些约束在系统的设计和测试中扮演了不可或缺的角色。
分层结构需求
很多项目通过利用分层或父子结构表达这些需求而受益。父子结构需求是利用父需求表达的特异性的一种扩大。父子需求为您提供了一种增强和扩大规范的灵活的方法,同时还可以组织提供的详细程度。只看父需求,很容易按照易被用户理解的方法提供顶级规范。同时,实施人员可以快速检查详尽的”子需求”规范,以保证他们能够理解所有的实施细节。
注意,分层结构需求由三种标准类型的需求组成–功能性、非功能性和设计约束。这里只定义了这些需求间的细化关系。
可跟踪性
除了为描述我们用来说明系统需求的事物而定义的术语之外,我们现在将注意力转移到关键关系,即可跟踪性,也就是在这些事项之间可能存在的关系。
开发出高质量软件的一个重要因素就是在规范、构架、设计、实现和测试阶段理解或跟踪需求的能力。历史数据表明变更的影响通常被遗漏,系统的小小变更可能带来显著的可靠性问题。因此,跟踪关系并在发生变更时关联这些关系的能力,形成了很多现代软件质量保证过程的关键线程,尤其是在任务关键活动比如安全关键系统(医疗和运输产品),和故障的经济成本很高的系统(在线交易)中,形成了一个关键线程。
下面看一下我们如何定义需求可跟踪性:
可跟踪性关系是一种依赖关系,其中实体(故障、用例和需求)”traced to”在某种程度上依赖于它”traced from”的实体。
比如,我们已经描述了如何创建一个或更多软件需求,以支持远景文档中给定的特性或用例。因此,我们可以说这些软件需求与一个或更多特性具有可跟踪性关系。
影响分析和怀疑
另外,可跟踪性关系超出了简单依赖关系的范围,因为它提供了利用我们称之为”怀疑”的概念进行影响分析的能力。当变更出现在”traced from”(独立)需求中时,可跟踪性关系就开始”怀疑”,因此必须对”traced to “(依赖需求)进行检查,以保证它与源需求保持一致。
比如,如果我们使用可跟踪性将需求与特定测试关联,并且如果诸如”Smartbot 应该能够存储和检索最多 100 条焊接路径”这样的需求变为”Smartbot 应该能够存储和检索最多 200 条焊接路径”,那么从该需求跟踪而来的测试就值得怀疑,因为为测试第一个需求而设计的测试不太可能适合测试第二个需求。
变更请求和变更管理系统
最后,变更是不可避免的。对于有希望成功的项目,管理变更的过程是必不可少的。不管它们的来源是什么以及来源如何众多,所有变更包括影响特性和需求的请求需要有序地被引进和管理。任何变更管理系统的关键元素都是变更请求本身。
我们将变更请求定义为:
对系统的特性和/或需求作出修订或添加的正式请求。 变更请求需要作为提议变更的结构化和形式化的陈述,以及围绕该变更的任何细节进入系统。为了管理这些变更,每个变更都要在系统中有自己的身份,这很重要。变更请求的简化形式可能为:
在大部分项目中,您会发现不缺少变更!实际上,您的问题是按照有序的方式管理、集成和(根据需要)拒绝不必要的变更。换言之,您需要一个管理变更过程。您的变更管理系统应该用于捕获所有输入,并将它们提交给变更控制委员会(CCB)来解决。CCB 由不超过 3 到 5 个代表项目关键涉众(客户、市场和项目管理)的人员组成,它管理和控制系统变更,因而在帮助项目成功方面扮演了关键角色。
结束语
刚一开始,我们就指出本文的目的在于帮助该领域的从业者提高他们回答下列基本问题的能力:
“系统究竟应该实施哪些行为?”
作为实现这一目标的第一步,我们定义和描述了分析人员以及负责描述问题域中问题的其他人员所使用的,用于表达将施加在预期解决方案上的需求的一些常见术语(比如涉众需要、特性、用例、软件需求等)。在这个过程中,我们还阐述了有效需求管理的一些关键概念。通过使用本文提供的术语和方法,您能够更有效地理解用户需要,并与开发人员、测试人员以及负责构建满足客户和用户需要的系统的其他技术团队成员交流提议解决方案的需求。
进一步定义和交流软件解决方案的其他更多关键方面的一项重要技术就是标准建模语言。统一建模语言(UML)是一种用于可视化、指定和文档化软件密集系统的工件的语言,并且提供了按照语义上更精确的方式表达这些技术构造的手段。本文的姊妹篇,Modeling the Requirements Artifacts with UML(利用 UML 建模需求工件),建立了更有效执行需求管理任务所必需的 UML 构造和扩展。
建议读物
[Leffingwell 1999] Leffingwell, Dean, and Don Widrig. Managing Software Requirements: A Unified Approach. Reading, MA: Addison Wesley Longman, 1999.
[Weigers 1999] Weigers, Karl. Software Requirements, Redmond Washington: Microsoft Press, 1999.
相关主题
- [Booch 1994] Booch, Grady. Object-Oriented Analysis and Design with Applications, 2nd ed. Redwood City, CA. Benjamin Cummings, 1994.
- [Booch 1999] Booch, Grady, James Rumbaugh, Ivar Jacobson. The Unified Modeling Language User Guide. Reading, MA: Addison Wesley Longman,1999.
- [Dorfmann 1990] Dorfmann, Merlin, and Richard H. Thayer. Standards, Guidelines, and Examples of System and Software Requirements Engineering. Los Alamitos, CA: IEEE Computer Society Press, 1990.
- [Jacobson 1992] Jacobson, Ivar, Magnus Christerson, Patrik Jonsson, and Gunnar ?vergaard. Object-Oriented Software Engineering: A Use Case Driven Approach. Harlow, Essex, England: Addison Wesley Longman, 1992.
- [Rumbaugh 1999] Rumbaugh, James, Ivar Jacobson, Grady Booch. The Unified Modeling Language Reference Manual. Reading, MA: Addison Wesley Longman, 1999.