UML软件工程组织

活用 XP:(四) 需求和故事
来源:IBM网站 作者:林星
如何分析需求,如何记录需求,如何将需求映射为设计,这些永远是需求分析中最为重要的问题。XP提倡以一种简单实用的态度来对待需求,而在软件开发的历史中,需求分析从来都是最需要严谨对待的工作流程。究竟谁是对的?

故事

每个人都喜欢听故事,这也许是从小就养成的习惯。如果能够把需求分析工作变成听故事的过程,那该有多好。需求分析人员写出一个个优美的故事,开发人员边看故事,边实现故事。也许这就是XP的设计思路所在。用户故事,XP把需求变成了一个个故事,摒弃了枯燥无味的需求稳定。文档的作用是传递信息,如果失去这个意义,再优秀的文档也没有任何用处。但是,完整细致、厚达数十页的需求文档是否真的能够达到沟通的目标呢?对于大多数而言,恐怕看到文档的厚度就已经心生惧意了吧。好吧,我们通过很多的辅助手段,可以强制要求开发人员都投入大量的精力来研究、学习复杂的需求文档。但是这厚厚的需求文档真的能够完整的记录所有的需求吗?更糟糕的是,需求是会发生变化的,到时候如何维护这份需求文档呢?回想精益原则,我们可以判定,这种处理需求的方式一定会产生大量的浪费。将需求做的尽善尽美需要成本,项目组的人员熟悉需求需要成本,维护文档需求成本,解决不一致的问题也需要成本。那么,我们可以针对这几点做一个分析:

  • 需求的文档是否要尽善尽美?需求文档的最大目标是将信息从业务人员传递给开发人员(当然也会存在其它的目的,例如作为合同的组成部分)。那么,文档是否完美和能否实现沟通效果并没有直接的关系。
  • 开发人员怎么才能够快速理解需求?文档的制作融入了制作者的思想,因此他人理解总是需要一定的时间的。解决问题的思路有两个:一是提供标准通用的做法;二是简化文档,简单的东西总是要容易理解,但简单的东西并不等同于制作容易。
  • 维护文档需要成本。不管如何,维护成本始终是无法避免的,关键在于,能否降低这部分的成本呢?维护成本和文档数量、复杂度成正比,因此文档的数量要尽可能的少、复杂度要降低。此外,减少维护的次数也是关键的因素之一,在讨论精益原则的时候我们说尽可能推迟决策就是这个意思。

针对以上的几点,XP提出了自己的实现思路-用户故事。用户故事简单,每个人都会写,每个人也都能理解,改变起来也很容易。但用户故事只是对系统功能的一个简单的描述,他并不能提供所有的需求内容,因此,在XP中,用户故事的实践需要现场客户的支持。用户故事之所以简单,是因为它只是开发人员和客户之间的一种契约,更详细的信息需要通过现场客户来获得支持。

从XP的观点来看,用户故事有这么几点作用:

  • 客户自己描述、编写需求。对于任何一个需求来说,最理想的状态都是开发人员教授客户编写需求。最差的情况是开发人员代替客户编写需求。毫无疑问的,XP要求的就是最优秀的做法。客户要能够自己开发需求,前提条件是编写需求的技巧应该足够简单,能够很容易掌握,或是经过培训很容易掌握。用户故事就是这样一种简单的机制。
  • 用户的观点。优秀的需求应该是站在用户的角度来思考问题,是用户能够利用系统完成什么,而不是系统自己完成。用户故事很好的达成了这一原则。因为用户故事是用户站在自己立场上编写,表现了用户对系统的期望和看法。
  • 重视全局,而不是细节。需求有精度上的差别,软件开发初期最关键的,是建立一个高阶的需求概况,而不是立刻深入细节。对于XP来说,最主要的细节需求获取的方法是经过现场客户。现场客户随时提供对需求细节的指导。因此,用户故事的重点在于,尽可能全面的发现需求,以及,维持一个简单的需求列表。
  • 评估的依据。用户编写的需求为软件的估算提供了依据。虽然这个依据是比较粗的,但随着项目的发展,开发速度的估算会越来越精确。在需求初期就进行适当的估算,其目的是让用户能够有一个比较直观的成本概念。这为用户制定需求实现的先后次序提供了指导。
  • 用户自己的统筹安排。制定用户故事就像是上商场购物,虽然每件物品都是有用的,但是最后购买的次序和数量则要取决于钱包的厚度。在每一个用户故事具有了成本(即上一条中的估算)之后,用户就能够权衡实际成本和需要,并排定需求的座次。
  • 迭代计划的输入。用户对用户故事的选择直接影响到迭代计划的制定,在第一个版本中,用户希望能够实现哪一些的需求(通过选择用户故事),经过估算,这些需求是不是能够在这个版本中实现,计划需要多长的时间。这些都是需求对迭代计划的影响。

故事的弊端

在收到国外汇款时,业务人员需要记录汇款的相关信息,如果汇款指定的收款人帐户为本行帐户,进行入帐处理,如果收款人帐户属于同城同业(本地的其他银行),则通过同城同业转汇给收款人(后续如何处理?),如果收款人帐户属于异地同业(异地的其他银行),则通过银行的帐户行将汇款转汇至异地,并支付帐户行转汇的费用(后续如何处理?)。

以上是一个银行的国际结算业务中款业务的例子。简短的叙述和非正式的形式体现了XP强调的简单原则。故事帮助开发人员和用户理顺流程的关系。在上述例子中,我们看到开发双方对流程仍然存在一定的疑虑(即括号中有问号的部分),但是这并不影响到用户故事的创作,因为这个版本的用户故事还会变化多次。但从这个简单的例子上来看,我们发现故事的形式仍然存在着一些不足:

故事的形式更容易被人接受,但是也有不规则的缺点。任意描述需求虽然节约了培训的成本,但是却造成了不一致性。不同的人对故事有着不同的理解,对需求也就有了不同的理解。需求故事虽然看起来很简单,但是要讲好一个需求故事绝对不是一件容易的事情。需求规约过于形式化和正式化,导致了需求规约难以使用,但是完全不要形式也不是一个好的做法。在形式和可用性之间保持平衡,是讲好需求故事的关键。

需求故事虽然容易阅读,但是却很难写得好。如何控制需求的描写精度,如何分解需求,如何组织,如何确定边界。但是XP并不关心这个问题,只要能够起到沟通的效果,怎么做都行。这种态度是否正确我们暂不去评价。但在实践中,由于缺乏系统的指导,一个新手往往需要花费很长的时间才能够学会故事的写法。

对于XP来说,需求的开发只有先后次序之分。而先后次序的制定由客户来负责。但是在实践中,识别出先后次序并不仅仅是客户的责任,开发人员同样需要提供需求优先级和风险的建议。这里有几点需求优先级的建议:

  • 需求中包含了主要的设计,或是包含了大量的业务实体和典型的业务规则。对于这样具有系统代表性的需求,应该赋予较高的优先级。
  • 需求中存在重大的技术风险,例如需求中包括了OCR开发包,而开发团队原先并没有相关的经验。
  • 需求中包含了重要的业务流程,代表了本软件的主要设计思路。
  • 需求具有代表性,并且难以估算,急需对需求进行试验性的评估,以获得较为精确的速度值。
  • 需求的时间紧迫。

采用用例技术

用例技术保持了需求的简单原则,用例和形式和用户故事非常的相似,但是用例具有自己的格式,虽然这个格式也是可以任意定义的。用例的重点是表示系统的行为。我们看看上面的例子如何用用例来表示:

主要角色:业务人员
层次:业务流程级别
前置条件:收到汇款
基本流程:
1 业务人员选择汇入汇款业务。
2 业务人员输入必要的汇款相关信息。
3 业务人员将汇款转入收款人帐户。
    3.1 如果收款人为本银行帐户,直接入帐。
    3.2 如果收款人为同城同业(本地的其他银行),则通过同城同业转汇给收款人(后续如何处理?)
    3.3 如果收款人帐户属于异地同业(异地的其他银行),则通过银行的帐户行将汇款转汇至异地,并支付帐户行转汇的费用(后续如何处理?)。
备选流程
暂缺

可以看到,用例表示的内容和用户故事并没有太大的差别,但用例比较强调格式。虽然不同的团队有不同的格式,但是在同一个团队中,尽可能使用相同和相似的格式(不同的用例可能需要不同的用例格式)基本流程中的每一个步骤都代表了业务人员和系统一次交互,流程非常的简单,但是已经覆盖了一个成功的流程。我们看到,流程的每一步都高度抽象的原因是该用例的层次是业务流程级别的。(业务流程级别也仅仅是一种约定,并不是标准)。利用层次的概念对用例进行精度的划分。在上面的例子中,低精度的用例主要的目标是把握系统的全貌。在RUP中,这种用例也被称为业务用例(Business Use Case)。在原先的用户故事中,对分支情况描述比较含糊,但采用了用例的这种描述形式,分支情况就一目了然了,和前面一样,分支情况的表述也有很多种的形式。

用例技术从提出到现在,已经有了大量的经验积累。在XP项目中采用用例技术并不是什么新鲜事。但在XP中应用用例也必须遵循XP的原则,以及精益编程的思路。所幸的是,这些思路是非常自然的,使用用例技术是完全可以实现的。本文并不打算详细的描述用例技术,如果要深入了解用例技术,有几本书是非常值得一看的(见附录)。

先把握系统的全貌:在做需求的时候,常常出现的一种情况是需求分析人员花费了很多的心思来精华、完善某个用例。对XP来说,这种做法并不推荐,而根据精益原则,这种行为存在浪费的可能性。我们对软件、对项目的认识是不断深入的。因此,我们在项目一开始就深入到需求、故事、或用例的细节,分析人员的能力可能很强,能够正确的捕捉到用户的实际需要。但是一个星期之后我们对需求的认识就有可能发生变化,也许是原先对用例范围的界定出现了问题,也许从另一个角度分析用例效果会更好,也许原先处理用例的思路不正确。不管如何,需求变化的可能性是非常大。用例越详细,发生变化的可能性就越大。这时候,原先花在精化用例上的时间就被浪费了。

因此,不要在一开始就精化需求,一开始的工作重点应该是放在尽可能全面的收集用例,了解整体的业务流程,分析主体业务流程等工作上。在获得了系统的全貌之后,你会发现你原先对系统的认识是不充分的,用例需要根据新的思路进行重新排列,用例的优先级需要调整,在UML图中,往往有一张系统的用例概览图,这张图所表示的就是系统行为的一个概述。

寻找优先级高的用例进行精化:我们在上文提到了需求优先级的判断,用例的优先级判断和需求的优先级判断相似。在讨论迭代的时候我们说过,前几次迭代的主要目的是要识别出项目风险。因此,寻找有代表性、优先级高的用例进行精化,能够帮助开发人员更快的理解领域知识,构建起初步的领域模型。

继续上面国际结算的例子,在完成总的用例图之后,我们发现,银行的业务非常的复杂,如果缺少领域专家,要在短时间内领会领域逻辑是非常困难的,同时,我们发现,汇款的业务在日常业务中所占的百分比是非常高的,而汇款业务涉及到了大多数的领域知识,而业务流程却相对简单。因此,我们决定,先把汇款的用例作为一个突破口,在完成了这个用例之后,我们的开发人员就会对业务领域有着比较深入的认识,也就能够进行更复杂的工作了:

主要角色:业务人员
层次:业务流程级别
前置条件:收到汇款
基本流程:
1 业务人员选择汇入汇款业务。
2 业务人员输入必要的汇款相关信息。
3 业务人员将汇款转入收款人帐户。
    3.1 如果收款人为本银行帐户,直接入帐。
    3.2 如果收款人为同城同业(本地的其他银行),则通过同城同业转汇给收款人(后续如何处理?)
    3.3 如果收款人帐户属于异地同业(异地的其他银行),则通过银行的帐户行将汇款转汇至异地,并支付帐户行转汇的费用(后续如何处理?)。

备选流程
2.A在任何时候,业务人员都可以应客户的要求对向汇款银行进行查询。
2.A1在收到汇款银行的查询答复之后,记录答复信息。
2.B在任何时候,业务人员收到汇款银行要求退回汇款的授权。
2.B1如果汇款未被提走,根据要求将汇款退回汇款银行。
2.B2如果汇款已被提走,通知汇款银行无法处理,用例结束。

注意到,在这个例子中我们对用例优先级的判定条件和上文的稍有不同,我们选择有代表性,但又相对简单的用例作为高优先级的用例。这样做是因为对业务领域比较陌生,一开始实现复杂的需求有很大的难度。所以,虽然我们提供了一些制定用例优先级的思路,但是实践的时候仍需要根据实际情况权衡。

迭代精化:用例的编写过程是一个对业务领域不断熟悉的过程。随着调研的深入,不断有新的问题显露出来,需要补充或修改原先的用例。这里有两种情况,一种是在同一个增量内,在对用例B精化的时候,发现用例A中忽略了一种情况,这时候我们就需要补充用例A。例如,我们在精化其它用例的时候,发现汇款用例中忽略了报表的需求,这样我们的工作又必须回到汇款用例上。这样的情况是非常普遍的,这就要求我们不要过分的修饰用例,不要把精力花在用例格式上,这样只会造成浪费。

第二种情况是在不同的增量中,这时候用例往往会加入新的需求、新的情境。我们如何去控制不同增量期间的迭代呢?一般来说,有两种方法,一种是对原有的用例进行增补,增补的部分用不同的颜色或标记。另一种方法是为用例建立版本,不同版本的用例对应于不同的增量周期。这样,对应对N个增量周期就有了n个不同版本的用例(n≤N)。不管是哪一种情况,都要求我们采用迭代的思路来处理用例。

形式不是最重要的:在团队中强制要求统一的用例书写格式是有意义的,但有的时候,这个意义并没有想象中的那么大。可以约定条件的编写形式、也可以约定层次的划分。但是过分的强制形式就没有什么意义了。

作者简介
林星,辰讯软件工作室项目管理组资深项目经理,有多年项目实施经验。辰讯软件工作室致力于先进软件思想、软件技术的应用,主要的研究方向在于软件过程思想、Linux集群技术、OO技术和软件工厂模式。您可以通过电子邮件 iamlinx@21cn.com 和他联系。
 
 

版权所有:UML软件工程组织