把用例应用到实时系统中的实践 http://www-128.ibm.com/developerworks/cn/rational/r-uc-rt/ |
|
|||||
Kerry 本文介绍了一个真实的范例,然后讨论了在把用例用来定义实时系统的规格时遇到的问题,以及相关的经验学习。 概述 本文的目标是:第一,重点描述实时系统规格的确定和用例之间的关系;第二,描述我们如何开发用例模型以及应用用例给我们带来了哪些益处。 要说明的第一件事情是为什么我们需要类似这样的一篇文章,然后我们再说明用用例来描述实时系统有哪些特殊之处。 在叙述为什么需要本文之后,我将描述一个具体项目和它的用例模型。我将重点描述用例模型的一些有趣的和有意义的特性,然后看看它们是如何有益于项目的。最后,我将讨论一些经验学习,并给出一些建议。 为什么我们需要这篇文章? 在为客户工作了这么多年来,我发现用例被广泛地误解。尽管有很多与之相关的书籍、文章和培训课程。可能这些书籍、文章和培训课程都只关注于问题,因此它们提供大量的不同的方法。在这些著作中经常提到的一个例子是自动柜员机(ATM)。类似这样的例子对于说明一些问题是有用的,但在处理很大而且很复杂的实际系统时却通常没有明显的帮助。在实时系统中你将怎样处理出现的问题?有一些实际的例子可以对你有所帮助,本文恰恰可以给你提供这样一个实际的例子。 什么是实时系统的特点? 实时系统也有最小限度的用户交互,对于这类系统怎么样定义它的用例是一件值得考虑的事情。实时系统通常都是高度算法化的,用例可能并不是最好的描述算法的文档方法。典型地,一个用例将引用在其它地方描述的算法。 如果你的系统具有有效的外部可视行为,那么用例能够极大地帮助你文档化你的系统需求。下面我描述的系统就有大量外部可视行为。在IT系统中应用用例的规则在这里仍然适用。 产品传送系统(PT)项目 这个系统中每个东西都很大。有的传送带有7公里长,需要15分钟才能启动。运行传送带网络需要一个复杂的控制系统。对控制系统的一个需求是减少运行系统需要的人数。另一个需求是降低对运行系统的人的培训需求。图1是工厂的航拍图。 图1: Hedland港工厂的航拍图 在左上角有一个船泊位。你可以看到有铁路线从右边连过去。卸货场在接近于中间的垂直线附近。在这个线的顶端是粉碎机。你可以在北面和南面的院子里看到仓库。传送带运行在卸货场和粉碎机,以及粉碎机和仓库之间。 你可以看到运输机从仓库装上铁矿,把它运到船上。运输机的容量非常大。在这个系统中,传送带可以在一小时内传送10000吨的铁矿! 有一些能够增加系统复杂度的需求非常值得关注。控制系统在避免溢出的情况下要达到最大的生产能力。出口容量在2004年从每年67M(百万)吨增加到81M吨,到2011年将扩大到90M吨。 基本概念:作业(route) 为了达到生产力的需求,控制系统采用激进的启动和错误处理策略。尽管已经存在的系统在一个时间点一个作业只能启动一条传送带,当它达到最大速度后,再启动下一条,依此类推。 新的控制系统在一个作业中将同时启动所有的传送带--注意我们的传送带的长度不同,启动时间和容量也不同。在出现问题时,新的系统试图尽可能关闭最少数量的设备以避免溢出,因为启动一个长的传送带需要15分钟。无论什么可能情况,设备都将保持运行,直到铁矿有可能溢出为止。系统需要同时运行作业,以便矿石能够传送到多个目标位置或者把矿石从多个源位置组合到一个位置。 设备失败的处理是全自动的。当一个传送带一小时可以传送超过10000吨矿石时,你可以想象出现问题时不能很快停下传送带的后果。这个结果并不是你可以用独轮车能够清理干净的!你将不得不使用一些重型设备来清理那些溢出的矿石,而且需要花费很长的时间。甚至有更坏的结果,比如一个错误导致矿石已经倒进了船的甲板上。 PT系统的用例模型 这里仅仅描述用例模型的一些特点,因为全部模型太大,也太复杂。用例的规范非常长,也非常细致。 识别角色(actor) 图 2: PT系统角色 在图2中,角色使用UML 包分组。在左边是角色包。最重要的一个在左上角。CRO 就是Control Room Operator,中央控制室操作员。其它重要的还有在左下角的RSMT(Root System Maintenance Technician,根系统维护技术员)。 其它的包包括所有不同的设备角色。一些用例提到我们管理的通用设备,另一些将提到特定的不同类型的设备。 在图的下方有一些与我们交互的外部设备。左边的一个是PMAC,一个已经存在的系统用来处理我们的用户界面。如果它仅仅是与我们的系统相关的用户界面,那么我们不需要把它看作角色,因为实际上角色是CRO。但是它实际上是我们相关的角色,因为我们给它传递信息,并且从它那里收集信息。 电力负荷管理系统Power Load Management System (PLMS)是值得关注的。在Headland港,港口工厂有自己的电站。当你启动7KM长的传送带,并在上面运行数千吨的矿石是,它需要大量的电力供应。因此,传送带的启动实际上是错开的,以便降低电站的负荷。只要你想启动传送带,PT系统都将询问电站并得到电站的许可。 确定用例 用例定义一个由系统完成的操作序列,它给操作者和相关人员提供 可观察到的有价值的结果。 在识别IT系统的用例时,牢记“可观察到的有价值的结果”是非常重要的,这一点在这里仍然适用。我们将看到系统提供给操作者和相关人员的值。在我们的例子中,中央控制室操作员是一个角色,但是整个公司实际上都可以看到系统把矿石从一个地方移动到另外的地方。“由系统完成的操作序列”声明了在用例中系统怎么做的描述。这些每个都是我们系统的需求。最后,用例是一个完整的有意义的事件流。把“完整的有意义的事件流”和“可观察到的有价值的结果”这两个概念组合起来可以帮助避免识别出不完整的功能片断并把它称为用例。 用例和角色在用例图中以图形化的方式描述。图3显示了 PT系统的顶层用例图。你很快就能看到 PT系统的用例分为4组:Operation, Administration, Configuration 和System Startup。 图 3: 顶层用例图 PT系统中用例相关的操作在图4中显示: 图 4: PT系统的用例 PT的主要用例是“传送产品”。正如这个用例的名字那样,你可以看到在这里系统提供给用户和有关人员的价值是把产品从一个地方运送到另一个地方的能力。这个软件也能够用来运送其它物品,不仅仅是铁矿。例如它能够用来在制药厂传送药片。传送产品是一个很大的用例,但它抓住了最根本的因素,即我们的系统存在的原因,即给我们的操作者和相关人员提供的价值。 在图4中我们看到与电源管理系统(PLMS)的交互,请求启动设备,我们也看到了用例与我们控制的设备的交互。我们可以显示每个设备角色,但那样的话,图就显得太混乱了。 在图4中,从CRO到传送产品的箭头,表示这个操作员发起或者启动这个用例。用例到设备和PLMS操作者的箭头表示这个用例或者系统与设备和PLMS交谈。从船舱装载系统(SHLS)的箭头表示SHLS发起与系统的交互--特别地,SHLS可以请求铁矿流暂时中断以便装载机移动到另一个舱室。 有关管理、配置和系统启动的用例在图5中描述。 图 5: 有关管理、配置和启动的用例 在这里我们可以做的一件事情是在对系统的操作影响最小的情况下更新系统软件。因此我们有"Perform Software Upgrade" 用例。我们也有"Start System" 用例 -这个用例经常被忘掉。系统有人身安全优先的规则,Start System 用例包括在系统启动时进行的所有安全检查的规格说明。你一定不想在服务人员在传送带上工作时偶然地启动它! Route System Maintenance Technologist (RSMT)是一个负责创建作业或者预定义作业的人,预定义的作业稍后由CRO使用。我们可以在系统中添加新的设备,定义新设备的种类以及定义系统传送产品的特点。港口工厂处理来自不同矿山的不同类型的铁矿,它们有不同的颗粒大小、不同的矿石成分等级。我们要非常小心的一件事情是避免把错误的矿石装到船上去。 关于用例图这里要警告一下:用例图只是冰山的一角。直到你开始写用例规格之前不要去重新分解、重组和调整用例模型。用例的规格大约95%来自用例模型。用例图仅仅给你一个模型的总体、全面的概要描述。 正如我前面提到的,用例描述“事件流”。图6显示不同种类的事件流和它们是如何在用例规格中描述的。 图 6:主事件流和分支流 从顶部到底端底蓝色粗线条表示主事件流(Basic Flow)。它表示每件事情都按照正确的方式发生。有很多种分支流(Alternate Flow)。描述处理设备故障的分支是一个很好的分支流的例子。另一个例子是描述操作员取消了前面请求的动作。 这里一个非常重要的结构是子事件流(Subflow)。子事件流就象子程序调用。我们试图保持主事件流简单易读,没有子事件流是很难做到这一点的。例如,我们使用子事件流来描述我们启动或者安放设备位置时发生的细节。这些过程每个都相当复杂,如果我们都在主事件流上描述,那么它将变得很长并且很难理解。 图7显示一个主事件流的片断: 图 7: 描述启动一个作业的主事件流示例 在第二步,系统检查作业是否有效。如果系统确认作业无效时会发生什么?这在分支流中描述。在用例规格中我们使用脚注来指示分支流,脚注文本包括指向相关文档章节的交叉引用。这将减少描述事件流的混乱,使得它更容易读。在这里我使用 "§" 符号指示存在一个分支流。我也用高亮的红色表示这是项目术语表--一份很重要的文档--中的定义。 在第3步,系统检查选择的作业的启动策略。"Starting/Positioning Stragegy 2.1"表示交错启动,它需要在启动作业前所有的设备都到位。这个启动策略在分支流中描述。最后系统向PLMS询问是否允许启动作业。如果不允许时发生的事情也在分支流中描述。 在图8中,我们将看到分支流和子事件流的例子。 图 8: 分支流和子事件流示例 分支流定义当基于某种原因设备不到位,因而这个作业不能启动时应该发生什么。系统给操作者发一个消息,建议在我们实际启动作业前把设备移动到相应的位置。在这个点上,用例就结束了。 子事件流的例子提供我们实际上如何启动作业的更详细的信息。系统检查全部作业设备是否畅通(传送带上没有其它物品)。如果正常,系统同时移动所有需要定位的设备到相应的位置,包括作业自己需要的设备和要与其它作业共享的设备,然后我们交错启动所有的设备以避免电力过载。当全部设备都运行起来后,我们告诉操作员作业已经启动,然后用例结束。第16步的 "a", "b" 和 "c" 也涉及了子事件流。 特殊需求 图 9: 特殊需求 第一个例子可以作为一个分支流,但是为了使主事件流基于阅读,我们可以简单地说:“系统检查是否有特殊需求的xyz节中规定的不能启动的状况发生”。在这个特定用例中,如果我们在码头传送带上还有东西,而传送带由于完成了往甲板上卸矿石已经停止工作,那么我们将给操作员发出一个警告。 第二个例子是一个算法的详细描述,这个算法用来调整传送带的传输量和传送速度。这里,主事件流可以简单地描述:“传输量和传送速度按照特殊需求中的uvw节进行调整。” 结构化用例 结构化技术在图10中显示。 图 10: 结构化用例 在图的左边,我们有一个用例,它有一个主事件流,一个分支流和一个子事件流。子事件流和分支流都可以作为单独的用例分出来。分支流变成一个新的用例,扩展了原始的用例。子事件流也变成一个新的用例,它包含在原始的用例中。一般来说,包含关系仅仅用于一个分支流共用于多个用例的情况。这就是我们如何确保仅仅写一个分支流,仅仅有一个维护地点的方法。通常,当需要在已经存在的用例上增加新功能而且你又不想修改原始用例时,可以创建一个扩展流 把这些结构化技术用到我们的产品传送系统后,改变后的用例如图11所示: 图 11: 用例模型的修改 这些新的用例称为“抽象用例”,因为它们没有操作者,你不能直接调用它们。如果我把这些抽象用例隐藏起来,你仍然可以相当清楚地看到系统的主要功能。 一系列的错误处理用例都以这样的声明开始:“当系统检测到设备故障”或者“当系统检测到超载”等。然后用例继续描述系统在这些情况的响应。 在图11的顶部,我提炼出了两个抽象用例:一个是启动作业,另一个是停止作业。从技术角度来说,我在这里破坏了规则:包含用例应当被多于一个的用例共享。我之所以这么做是因为,如果我在“传送产品”用例中写出所有的内容,文档将超过300页。把它分开可以让很多人同时在系统的不同部分描述需求。 补充需求 下面是放在补充需求中的非功能需求的例子:
功能需求也可以包括在补充需求中。当有些功能用用例写还不如用补充需求描述时,可以把这些需求放在补充需求中,而不用写一个完整地用例规格定义。下面是一些这样的例子:
用例的益处
另一方面,关于用例有很多不正确的观点。第一个是,象当前多种书籍和文章中指出的,传统的书写需求的方法能够更严谨和精确。实际上并不是这样的,我们在这个项目中也能写出非常严谨而精确的用例。 另一个看法是任何没有经过专业培训的人都可以写用例。写传统需求文档的原则在这里仍然适用。你需要从外部视角来看系统做什么。你不需要写出系统是怎样做的。象传统的需求一样,你写的用例需求也应该是可测试的。新手经常继续使用老的诸如功能分解的习惯。有开发背景的人经常倾向于从系统内部而不是用外部视角描述。 用例贯穿整个项目 项目计划
用例分析 图 12: 从启动作业用例导出的序列图 测试计划 图 13: 从启动作业用例导出的测试用例 经验学习 2. 不要引入设计。这与经验1相关。下面是一个例子 每个作业都拥有一个使能信号,这个信号来自于作业的运送源。使能信号在操作间内部驱动作业运送来源的物理信号。(用例在这里描述了系统内部信号。) 有很多原因使你不应该这么做。首先,它使得测试很困难,因为描述的行为在外部不可见。第二,如果你把设计信息放到用例中,你就需要照着这些信息实现,因为那是需求,因此你不仅必须照着它来进行演示说明,而且它也限制你的设计人员的实现方式。 3. 不要为内部监控过程写用例。在这个系统中,由于是实时系统,有很多在系统内部运行的过程用来检查、监控和轮询其它设备。你不应该在你的用例中描述这些,因为它是设计,它仅仅是一种可能的实现方式。 除非过程与系统的目标相关,例如在建筑监控中的“监控建筑”用例中,你应该把它们写在补充需求规格中。例如
在用例的分支流或者扩展用例中,都可以描述如果系统检测到问题时发生什么事情。这些需求可以使你设计诸如轮询设备或者设备产生中断等的过程,然是它们属于设计应该考虑的事情,不属于需求的范围。 4. 不要太早"冻结"用例。在项目中太早冻结用例将会导致很多问题,因为在你和你的客户更好地理解需求时,你可以找到机会重新组织用例,或者你将引出新的用例,或者你要修改现有的用例。需求变更会发生,但这需要在一个迭代过程的管理和限制下进行,以便进行适当的影响评估,以及合适的预算和计划日程的变更。如果你使用迭代过程,你至少有在后面的迭代中改正的机会。 5. 不要过于追求完美的用例模型而超出项目计划日程。这是经验4的必然结论。你从来都不可能得到一个完美的用例模型。在某个点上,你将不得不停下修补完善用例模型的工作,开始实际的系统开发工作。即使用例模型并不完美,你也可能开发出符合用户需求的系统。最后,图14显示PT用例模型的实际样子。 图 14: 不完善的用例模型 你将看到选择作业、启动作业和停止作业是主要的用例。这里并没有围绕着传送产品用例把所有其它用例联系在一起,我们不得不在附加需求中描述其它的需求。来自操作员和相关者的选择、启动和停止作业的需求并没有进行评估。用例模型不完善的主要原因在于,需求必须在某个点冻结,以便开发者不会频繁地面对不确定的开发目标,系统应当被实际开发测试和部署。 6. 不要害怕收集细节信息。用例假定容易被每个人阅读,但是这并不意味着你在大街上随便找一个人,给他一个描述复杂系统的用例,就能够期望他能够理解。 需要问你自己的问题是:你的客户需要多大程度的细节?你想给你的开发者多大的范围?如果你在用例中没有给出很多细节,你就让你的开发者自行作出决定。你想这样做吗?你的开发者可能有丰富的经验而你也很高兴这么做。另一方面,如果你正在进行实际的开发,没有充分的细节不一定是可以接受的。你需要给开发者和测试者描述以足够的细节信息,说明什么对于客户是重要的。 如果有大量的细节信息,可以考虑把它们放到特殊需求或者附加需求中,或者用活动框图(Activity Diagram)来补充用例。(参见经验9) 7. 不要引入用例间的直接交互。用例不能相互交互。它们可以相互影响,但是只能通过操作系统状态来影响。 8. 不要把有关解决资源争夺问题的架构决策放到用例中。这一点与第2课有关,例如,当操作员使能一个作业的来源时,同时第二个作业共享同一个来源因此得到一个来源不可用的错误时,会发生什么情况? 这些状况应该在不同的用例中描述。在每个用例,你只需要简单描述在给定环境下你想要系统做什么。在这个例子中,系统内部如何工作,什么信号发到设备,这些都属于架构或者设计问题。系统架构需要解决这些问题,诸如保证信号在非常接近情况下接收、不同顺序接受或者高频率地接收。 9. 使用活动框图以便使得复杂的用例能够易于理解。活动框图可以作为用例的规格创建。 总结 对任何系统来说,在确定用例时,要集中在系统的目标上以及系统给相关人员提供的价值。在写用例时要维护一个系统的外部视图。 对于实时系统,附加需求在整个系统需求中占有更大的百分比。
|