UML软件工程组织

轻巧建模之需求篇(二)
来自:cn.geocities.com 作者:Scott W.Ambler
需求初始阶段(IRUF)
需求初始阶段(IRUF)发生在整个项目生命周期的开始,对应于Rational Unified Process(RUP)(Kruchten,2000)中的Inception phase和XP中的第一个迭代之前。它有三个主要的目的:第一,至少从高层次上确定系统的范围,以明确你所要做的工作的范围;第二,定义系统的高层需求;第三,对于需求的含义,在甲方和开发项目组间取得一致。如果你和项目甲方在同一个地点,而且他们能就该系统应该做什么达成比较一致的意见,这个阶段可能只需要几个小时;否则的话,有可能会延长至几天或数周(参见“解决需求分析建模中的常见难题”一节)。你可能需要召开一个大的建模会议,主要是实现需求初始阶段的这三个目的。这些会议有如下特点:
§ 时间长。对一个大的项目可能需要几天。
§ 有许多项目甲方参加,以便广泛地听取他们的需求。
§ 趋向于比较正式的形式(主要由于参加会议的人数众多,而且项目甲方对哪些灵巧的方式并不熟悉)。
§ 包括一些开发人员。尤其是当你开始想让项目组理解该系统是完成什么样的功能时。
系统范围的定义可能用一句话就够了,对SWA Online就可以简而言之为“通过互联网向客户出售产品”或者详细一点的如“在美国本土向新老客户出售有形的而非虚拟的产品”。系统范围同样可使用环境模型(context model)来定义,该模型表示你的系统如何适应所有的环境。它经常使用使用案例图进行表示,参见图5;或用数据流图(DFD),参见图4(常叫做level-0 DFD)。搞清楚系统的范围非常重要,只有这样才能限定你的开发工作。上面的第一句话过于笼统,它可能意味着面向的是国际上的客户,明显这比仅针对美国本土客户的工作量大很多。同样,出售虚拟产品如在线音乐需要另外一套在线交付系统的支持。随着时间的推移,这个范围有可能由于甲方的决定的改变而变化,所以时刻准备好迎接变化。

图 4用数据流图(DFD)建造的SWA Online的环境模型

图 5 用使用案例(Use Case)图建造的SWA Online的环境模型
那么哪一个最适合描述系统范围呢?一句话,DFD,还是使用案例图?根据你的情况而定。语句直接了当,但不如图形的内涵丰富。图4的DFD以所要建造的系统为中心,表述了其与其它外部实体(组织、人或其它系统)的关系,这些外部实体超出了你的系统的控制范围但与你的系统有相互作用。这种方式的主要优点是它以合理的细节描绘了你的系统与外界间的主要信息流动。图5的使用案例图同样以所要建造的系统为中心,以及与该系统有交互的参与者(组织或人)。它的主要优点是描绘出与系统有交互的外部的和内部的参与者,而DFD仅有外部的。主要的缺点就是它没有给出任何一点系统与参与者交互的细节。你应该使用哪一个呢?他们都有各自的优缺点,你可能会考虑都使用。嗯… …?这对我而言不是很灵巧。一个较好的解决办法就是稍稍违反一下规则,结合这两种方式优点仅生成一个图,就象我在图6中所作的。注意一下我的风格:在两个实体的左上角用“I”表示出这是内部实体;移去了DFD中的数字标识符(数字标识符难于人工维护),我宁愿遵循一定的规则以使实体的名称唯一,在需要时这个唯一的名称可以起到标识符的作用。虽然我选择了显示数据流而不得不打破一些使用案例图的规则,但我仍然能够轻易地使用使用案例图的符号。幸运的是我的项目甲方喜欢DFD,我也就投其所好了。记住有目的地建模这条原则就是要你了解你的听众,选取最适合他们的artifact。
不要害怕打破规则。一般经验告诉我们不要在level-0 DFD中包含内部实体,引入内部实体意味着你开始挖掘细节。但我之所以在这里却选择了这样做,是因为它能让我不用再画第二张图。我不会因此而死到临头,也不会招致建模警察的控诉。是的,我违反了应用建模标准这一条做法,但这样做我减少了开发和维护的费用。当这对于某些人成为一个很大的问题时,我想我的组织可以重新考虑一下标准。

图 6 使用包含内部实体的DFD建造SWA Online的环境模型
为了确定系统的高层需求,我推荐采取基于使用的方法, 即注意力集中在用户如何利用该系统工作这一点上。根据我的经验,这是一个对绝大多数的软件开发都有效的方法。如果你对用户如何使用系统没有一点概念,很难想象你所生产的软件能够支持他们的工作和改善他们的工作方式。我会将这个方法用在建立组织内部使用的商业应用,由客户所使用的商业软件,包装出售的软件(如CASE工具或文字处理软件),数据仓库的开发,甚至于集成现有的商业系统(COTS)如SAP R/3或Oracle Financials。在数据仓库系统的开发中,存在着一个普遍的错误,那就是首先收集“数据需求”。罗列出用户想存储在数据仓库中的数据元素或数据实体。乍看上去,这是个好主意,但如果你不知道用户如何使用这些数据,那么你很难定出优先级或者你根本就不清楚你所做的是否就是甲方所想得到的。对于COTS系统,你需要根据需求来选择使用何种建模方式。如表1所列出的有特性(Feature)、使用情景(Usage Scenarios)、使用案例(Use Case)和用户故事(User Stories),这都是比较好的方式。根据使用恰当artifact这一条,我会选择使用案例,因为SWA采用EUP作为软件开发的主要流程,而使用案例是最适合于这个流程的。如果他们选择的是XP,则用用户故事为佳。如果为Feature Driven Development(FDD)(Coad,Lefebvre,Deluca,1999),那特性就是我的选择。
图7是一个高层的使用案例图,它是一张数字照片,来自于我和我的项目甲方讨论时在白板上所画的图。这是一个基本使用案例图(Constantine & Lockwood, 1999; Ambler, 2001a),因为它以技术无关的观点来显示系统。基于这张图,你既可以全手工的方式来实现这个系统,也可以建造一个全自动的系统。其中的一个使用案例“Post Product Review”可以改名为“Write Product Review”以使之更趋于一般化,但我的项目甲方更偏爱前者。我一直在为尽可能地使需求无关于特定的技术而努力,但事实上许多系统已经局限于某个领域内。例如,SWA Online被限定为基于互联网的解决方案之上,此时如花费精力去尝试将其抽象出来,只会得不偿失。记住保证甲方的投资获得最大利益这条原则,将你的精力集中在能带来效益的那些需求模型上。

图 7 一个高层的SWA Online使用案例图
使用案例应力求简单,在初始阶段(IRUF)对每个案例有一点提纲挈领式的逻辑描述就足够了。你不必在此时进行细化,你仅需要对该系统的用途有个基本了解,确定初始的范围,再对每个使用案例和参与者加一点提纲挈领式的描述。如果得到项目甲方的认可,你就不用花费更多的精力在初始阶段。可能三到四个使用案例就足够了。然后遵循有目的地建模这条原则,我们就可以终止初始阶段的工作,进入到详细建模阶段去建立详细的模型和实现你所确定的这些需求。注意这种方法更多地是运用在实行XP的项目中,而非实行UP的项目中。
你们可以看见在图7所示的需求图中我使用了UML的构造型(stereotype )<<Include>>,然而在《The Object Primer 2/e》(Ambler, 2001a)一书中我曾建议在分析层次的使用案例图中使用构造型(stereotype),典型的如系统使用案例图,因为它们经常反映了架构和设计方面的问题,而需求层次的使用案例图却并非如此。同样,我也不会因为如此而受到建模警察的控诉。这个图是有意义的,因为它显示出它对处于流程中不同阶段的模型是公共的,在这里它表示我要考虑的包含需求和分析两方面的问题。
要在项目甲方之间达成一致的意见,这说起来容易,作起来难,尽管你有了“解决需求建模中的常见难题”这几招。每个甲方的背景、优先权和喜好都各不相同。为了达成一致意见,每个人都必须认识到这点,相互交流他们需要从该系统中得到什么,倾听他人的意见,准备为了达到一个共同的目标而努力。在我所工作的组中,只要发生意见分歧,我们都会在屋内所有人都能看见的一块白板前写下每人的问题,再进行讨论。这种方式将这些意见的不同之处可视化,可以集中讨论的焦点。在某个问题的提出者认为它不再需要或至少相对于其它问题不那么重要后,我们会将它擦去。虽然有时它是一个较好的意见,但也简单地将之擦去,因为通常我希望记录的是最后的决定。对于两个相互对立的问题,我喜欢在它们之间画一条其它颜色的连线,以突出它们需要进行讨论。
由于我们集中在高层次的使用需求上,相关的业务规则和约束常常也会被同时确定下来。同样,一些技术需求和将来可能或不可能被实现的需求也会确定。在初始阶段(IRUF)你应该将业务规则、约束和技术需求排列出来,常用的方法是将它们写在粘贴纸上或白板上,找出你是否已具备了足够的信息以进行后一阶段的工作。尽快地结束初始阶段的目的是防止你在这个阶段就投入时间探究细节。当你在初始阶段需求讨论会上就进行细节的讨论时,你就给你的项目带来了风险,因为此时你不会收到对你工作的具体反馈,从而陷入分析的泥潭。记住这条原则你的主要目的是软件,而不是那些设想你的软件如何运作的模型和文档。例如在SWA Online的初始需求建模会上,项目甲方提出了一些业务规则和执行顺序的约束,象如何打包某类的货物,某些产品具有一定的上架时间限制,以及分捡流程。当我听到诸如此类的需求时,我就会叫某个人将其写在白板上或索引卡片上,稍后再将这些索引卡片放在每人都能看到的公用桌上。
这里有一个重要的观点:建模会议是交互的,每人都参与其中的。会议的开始需要一个有经验的模型设计者来段开场白,解释一些技术,推动与会者进入状态。这可能就是简单地叫某人走上台来,解释一下正在谈论的内容,演示一下通过填写一张索引卡来总结一条业务规则,或者为一个可能需要的报表在粘贴纸上记录下数据的要求。当与会者熟悉了这种建模方式后,依照灵巧建模的甲方的积极参与这一做法,你会发现不用花太多的精力去鼓励他们的参与。是的,有些人比较开始害羞而需要更多的鼓动,但那毕竟是人的本性(如果我能选择的话,我更喜欢选择那些外向甲方的加入,而非那些内向不愿开口讲出他们意见的人)。
当你的开发组在确定目前版本的需求时,常常伴随着一些后续版本的需求或一些你可能在某时需要实现的潜在需求。虽然此时你不想过多地深究,而且你也不想实现过多的功能去满足这些潜在的需求,但你并不想就此丢弃它们。它们也是有价值的。这些潜在的需求可能会影响到你对系统架构的选择。变化案例(change case)(Bennett, 1997; Ambler, 2001a)是一项用于记录潜在需求的简单技术,图8是SWA Online中的两个变化案例。在定义项目范围时一项重要的工作就是指出哪些需求是现在应该实现的,哪些是超出范围的。变换案例中的需求就是超出当前项目范围的。如何有效地使用变化案例的详细内容可参见Agile Architecture一文。
 
变化:扩展至北美地区
可能性:非常可能
期限:12-18个月
影响:
§ 必须支持向加拿大和墨西哥的用户交货。与新托运商的关系需要建立。
§ 需要计算相关的税收和关税。
§ 由于法律和当地风俗习惯,在这些市场出售的产品有可能会有所不同。
§ 多语言支持(英语和法语是加拿大的官方语言,墨西哥是西班牙语)。
变化:销售虚拟产品(在线音乐、录像、书籍… …)
可能性:非常可能
期限:6-12个月
影响:
§ 不能与实际产品的运输流程混在一起。
§ 我们可能需要对某些产品支持数字许可。
§ 个别产品的销售可能有某种限制(有效时间、拷贝数量)
 
图 8 SWA Online 的两个变化案例
那么你需要多少文档来记录项目的范围,初始的、高层次的需求呢?就象我在Agile Documentation一文中所建议的“刚好够用就行”。对于SWA Online这个项目,我们也许建立一个HTML页含图6的环境图,图7的使用案例图,和一个简短的指出范围的列表就够了。为建立高层次需求文档,我会尝试将使用案例转写在一个单独的能进行文字处理的文档上,或者就是一个简单的文本文件。之所以这样做,是因为在详细建模阶段我们要细化它们。有这样一份电子文档使得共享和处理更容易。至于那些记录了业务规则、约束、技术需求和变化案例的索引卡片,让它们保持原样,因为它们会在详细建模阶段得到进一步的细化。我会让我的项目甲方相信,如果我们发现它们确实是需要的,我们会处理的,因为我们那时需要它们。这样由于避免了一些有可能不必要的在文档上的工作(有些业务规则是不合逻辑的,因此在你知道它们的真正价值前所投入在文档上的工作都是浪费),就可以使得开发组能够很快地进入详细建模阶段,然后进入实施阶段。
详细需求建模阶段
一旦系统的范围和高层需求得到认同,基于该阶段的成果,你就可以开始为你的开发工作制定进度,将这些需求带进一个迭代过程(iteration)。该计划随着你对需求的理解的不断发展而演化,由此你就开始了真正的开发。
迭代过程的开始
在这个过程的开始阶段,这些需求会分发到各个开发者手中。在一个实施XP开发流程的项目组中,开发人员会结成对子,自愿地对给定的用户故事进行处理。每个用户故事都以相同流程得以处理,这个过程不断反复直到处理完所有的用户故事。实施UP的项目组或者以类似的方式运行,或者由项目经理将需求分配给某个开发者或一个小组。无论以何种方式,开发小组/对子都处于实现这些需求的状态。第一步就是要详细了解你的项目甲方想要得到是什么东西,这可能需要进行一些需求建模分析。
在这个迭代过程的开始阶段有两种方式进行建模工作:
集中所有需求在一起进行建模。采用这种方法,整个项目组以及能到的项目甲方会在一起探讨详细的需求,分析这些需求,对已有的系统设计提出修改建议以支持这些需求。假设这整个迭代过程是两个星期,我希望这个会议的持续时间一个小时到半天。如果这个过程更长,假设四到六周,你可能需要花一整天的时间在这上面。这个时间不希望超过一天,因为你不会收到具体的反馈,具体的反馈只有当你用代码验证它时才会得到的。这个方法的优点是可以对所要进行的工作和打算如何去做有一个具体视图,而且可以得到所有项目成员的想法,因此增大了确立一个良好开端的机会。它的缺点就是只适用小项目组,一般少于十个人。而且也比较浪费时间,因为不是与会的每个人以后都要参与各个方面的工作。注意一旦完成了这个初期阶段的工作,每个开发小组仍然需要对它们所负责的部分进行详细的建模。
各个开发小组对它们所负责的需求直接进行建模。有些开发组会在迭代过程的开始阶段放弃以上做法,而简单地就直接让各小组进入到其所负责的部分。这种方式的成功需要有这样的前提:需求间没有联系,或至少联系不是太多;开发人员遵循集体所有制这个做法;基于共有的代码之上。它的优点就是能够使得项目组在迭代过程开始的第一天就进入详细分析建模。但它有几个缺点:第一,当需求映射到设计上有交叉时,可能有两个小组都在处理有关定单计算的问题(比如一个小组负责计算税款,而另一个小组负责折扣的计算),这就会有两个小组工作重叠的风险。但这不算一个严重的问题,因为每个小组都应该知道其它小组正在做什么,当需要时可共同工作。第二,这会经过较长的时间后项目的整个实现视图才会明了。第三,在开始会引起对项目甲方的争夺,因为每个小组工作的开展都需要从他们那里得到输入。
迭代过程中
一旦结束了开始阶段的工作后,项目组很快就进入到持续的迭代过程中,建模、编码、测试、编译,或者进行软件配置。你和项目甲方的大部分需求建模的工作会在这段时期中体现,这个过程的目的就是探究、细化这些需求。实际上,更准确地说这些工作就是一些建模会议,因为你可能会不断地重复着需求、分析和设计。这些会议一般是由一小组人即席召开的,一般包括开发小组成员和由一个或几个项目甲方提供输入。这类会议一般讨论某一类别的问题,如“莎利,你能花几分钟时间讲一下客户是如何搜索一个定单的吗?”。
那么我在SWA Online这个项目中是如何进行详细需求建模的呢?首先,假设我们有两个人结成对子。在这个迭代过程中,我们要实现定单的定义和使用案例中“下定单”(Place Order)这个行为的基本路线(basic course of action)中的定购部分。在这里,我们不去实现查找功能,任何类型错误和异常的处理,税金计算和折扣计算[1]。一个行为的基本路线常称为“愉快路径”(happy path),因为沿着这个基本路线所有操作都是正常的、愉快的。行为的备用路线(alternate course of action)是描述当有不正常的操作时所走的路线,这里比如一个用户向一个缺少存货的产品下定单的情况。我们现在仅关心“愉快路径”,其它的需求会由其它的小组或者我们在以后处理。
我们要做的第一件事是充实这条基本路线的逻辑过程,如图9所示。同时也进行关于这个使用案例的基本用户界面原型的工作,如前面的图2所示。之所以我们要并行地进行这两部分工作,是因为它们从两个不同方面来解决这个问题。使用案例描述的是用户在下一个定单时要做什么,基本用户界面原型则是构造一个支持该行为的用户界面。请注意使用案例“Place Order”利用构造型(stereotype)<<Include>>调用了另一个使用案例“Search for Item(s)”,见图7。虽然这个功能是该使用案例中的一部分,但我们并不在这里实现它,因为它超出了范围。我们会采用另一种方式来替代,有可能就是直接给出一个假设的查询结果的页面。这个查询功能会在稍后恰当的时候实现(记住,我们使用的是增量的方式)。同样现在也没有考虑任何类型的技术问题,我们会在以后的分析中或设计中决定这些问题。现在我们只是想了解这个下定单的基本过程,稍后(可能就几分钟后)我们才关心实施的细节。对那些我们不会在这个迭代过程中实现的逻辑步骤,比如税款和折扣计算,当我们在编码时会留下接口。
 
  这个使用案例从一个用户选择下一个定单开始。
用户通过另一个使用案例“Search for Item(s)?”来搜索物品。
用户选择一个物品并加入到他/她的定单中。
用户指定他们想购买该物品的数量。
系统通过该物品的单价和购买数量计算出总价。
用户重复第2步到第5步继续订购其它物品。
用户结束向他们的定单加入物品。
用户提供送货信息和付款信息,包括他们的名字、电话号码和邮寄地址。
系统计算定单中所有物品的总价。
系统按照“Calculate Taxes for an Order”这条规则计算适用于该定单的税款。
系统按照“Calculate Discount for an Order”这条规则计算适用于该定单的折扣。
系统显示税款和折扣。
系统加上税款和减去折扣,得出最后的总价。
系统显示该定单的汇总表。
用户验证该定单是否正确。
系统为该定单下计划(参见使用案例“Fulfill Order”)
系统给出一张该定单汇总收据。
图 9 下定单的行为基本路线
虽然我们知道该系统使用浏览器进行操作,但我们不会现在就用一个HTML的编辑器进行用户界面的设计,而是仍旧使用粘贴纸。因为在用户界面设计的初期,我们会经常地很频繁地增减控件、改变布局,我们希望用一种工具来支持,而粘贴纸所具有的灵活性和弹性正是我们所需要的。当这个页面的布局稳定下来后,我们会转到HTML编辑器上,因为我们此时想生成一个更加具体的界面可以让甲方进行评估。眼下,我们就简易行事。
在这个阶段,我们遵循了灵巧建模的几个做法。明显的有并行建立多个模型(Create Several Models in Parallel)这一条,因为我们同时进行了使用案例和基本用户界面的工作;有同他人一起建模(Models With Others)这一条,因为包括了两个我们的开发人员和至少一个负责提供需求的甲方;有简单地建模(Depict Models Simply)这一条,通过图2中的这个简单模型我们可以看到这点;有创建简单内容(Create Simple Content)这一条,图9所示就是一个很好的例子,它刚刚好足够详细地描述了使用案例的业务逻辑;有使用恰当Artifact(s)(Apply The Right Artifact(s))这一条,业务规则不在使用案例中体现而在另外单独的业务规则artifact中,虽然你可能会提出异议“计算定单的总价就是一条简单的业务规则”(此时,对于计算定单的税款和计算定单的折扣这两个业务规则,你可能会在文档或所引卡片这类用于业务规则的artifact中预留下位置)。此外,用户界面的需求使用的也是另外一个artifact,即基本用户界面原型。如果我们还有数据方面的需求的话,它将会使用概念模型;有切换到另外的Artifact( Iterate To Another Artifact)这一条,当我们在用户界面原型上增加了一项时,会发现在使用案例中缺少相应的逻辑,反之亦然,这时我们就会在使用案例和基本用户界面原型间来回修改;最后,也用到了使用最简单工具(Use The Simplest Tool)这一条,用户界面原型用的是纸张,使用案例逻辑写在白板上。
一般我们花费在上面建模的时间是三十至六十分钟。假设我们对建模的结果感到满意,要么就会继续进行分析和设计工作直至编码,要么会先花上几分钟时间用刚才所学到的去更新一下项目组的概念模型。我建议使用尽可能简单的概念模型,就像图3所示的CRC卡片,因为它们易于使用而且非常容易被项目甲方理解。它们不仅用来表示系统中主要的实体,而且可以表示出这些实体的职责(包括数据和行为)。对于概念建模,你下一个最好的选择就是采用UML的类图(class diagram)。它的优点在于能够表示出类或实体间的关系,例如多重性(multiplicity)和角色(roles)。CRC模型中的类合作者就隐含地表示了类之间的关系。问题是对于你的项目甲方来讲,类图不如CRC卡片那么容易理解,即便他们努力地积极参与,但类图还是过于复杂了。传统上数据模型用于概念建模,经实践验证即使当使用结构化的技术进行实现时也是可行的,但UML的类图却难以做到。
尽管我在这里所讲述的建模工作很有可能花不了一个小时,但你可以很容易地组织你的建模工作,更好地进行划分。或许首先集中解决前几层的使用案例及其相应的用户界面,实现这部分的功能,然后再回过头来解决下几层的使用案例。这种方法在两层的时候工作得很好,你应该采用最适合你自己的方法。
认识到在这个迭代过程中需要不断地反复是很重要的,当需要时就要回到需求建模的工作上。当你开始实现下定单这个功能时,有可能会发现你对其工作的细节并不清楚,比如对某类物品可能有购买数量的限制。如果发生这样的情况,你就会有新的功能需要进行评估、要指定优先级和将其带入以后的迭代过程中。有可能你的逻辑顺序颠倒了 – 客户可能应该首先提供送货和支付信息;还有可能应该提供一种能让客户一次性地建立他们送货和支付信息的途径。总而言之,新的需求必须要在新一轮的迭代过程中加以处理。
 
 

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