9月下旬,UMLChina首席专家think在上海开设了一次主题为“UML应用实作细节”的公开课。在为期两天的课程中,他主要讲演一种应用UML进行OOAD的软件开发过程,该过程将软件开发划分为多次迭代,每次迭代包含以下几个主要步骤:
第一步,捕获系统需求,得到用例图和有价值的需求文档;
第二步,从用例文档捕获实体类,得到类图;
第三步,使用顺序图,为类分配职责。
第四步,针对具体平台进行设计,精化前面得到的类图和顺序图。
此后可很容易得到系统架构,并将设计结果转化为代码。不失完整性,不妨加上第零步:业务建模。该过程体现了敏捷建模的原则,紧抓UML中最重要的东西,在必要的时候考虑加入其他元素。结合这些天在项目中的实践情况,谈几点主要的体会。
一、 构建软件,最困难的是需求的捕获。
开发软件,到底最困难的地方在哪里?布鲁克斯(《人月神话》作者)在他那篇著名的论文《没有银弹》中说的很清楚:构建软件系统,最困难的部分就是精确决定到底构建什么。业界专家也告诉我们需求是变化的,不明确的,甚至是误导的。在这两天的课程中,think把一天多的时间花在用例身上,正确捕获需求的困难,由此亦可略见一斑。
我个人对需求捕获的困难也深有体会。在以前的公司,老板经常会跑到办公室里描述客户新的、变化的愿望,我们开发人员只能硬着头皮去修改软件,使之适应变化、包含新的功能。其时此时我们并不清楚客户真正需要什么,又或者说客户自己都不清楚自己想要什么。最怕的是折腾了几个星期后,老板说客户还是喜欢我们从前的软件。我们其实什么都不用做!来到DT(注:作者所在公司)后,由于自己不是通信专业出身,很多业务上的问题都需要不断地向同事请教,并查阅一些相关的资料,否则就无法进行分析设计。
既然需求捕获是最困难的,那么从风险的角度来看,它也应该是最重要的。我们除了在思想上愿意为需求付出相应的代价以外,还应该在行动上以一种正确的方式去捕获需求。
首先,应该有正确的需求队伍,即用户+业务专家+开发人员。从本质上来讲,需求是用户的需求,应该体现用户的价值,而不能是开发方的想当然和一厢情愿,做商业软件尤其应该明确这一点。不能为客户创造价值的软件,那将不能成为商品,最多只能成为自己的玩具。对付需求风险最重要的要素之一是熟悉领域的专业知识,不接近领域专家是项目失败最常见的原因之一。
其次,应该立足用户视角去看待问题,并以一种合理的结构去记录需求结果,这样才能够有效应对需求的困难和易变。很显然,开发人员喜欢站在自己的立场去考虑问题,这种习惯体现在需求中往往是“系统做什么”,而根本没有“用户做什么”,“用户希望系统做什么”。开发人员喜欢那些具体的概念,如“下拉菜单”、“OK按钮”,而这些东西往往最易变化,最难维护。
UE应用软件小组在前期是以用例来捕获需求的,在此期间出现过很多很多的争议,现在回过头,我想对用例的使用的要点做如下总结:
1. 把用例和参与者的目标连接在一起;
2. 将基本流和可选流分开;
3. 不要把步骤当用例;
4. 将设计说明排除在用例之外;
5. 界面设计是设计,是脆弱易变的,不应该被包含在用例文档中。
需求不清楚,目标不明确,软件开发是打移动靶,还是南辕北辙,时间和竞争对手会给出答案。
二、 使用UML建模,最重要的是问自己,如何向下指导生成代码。
使用UML的基本理由之一是交流,它既保留一定程度的精确性,又不失细节。UML还可以帮助人们迅速获知系统全貌。这一点可能很多人都有所体会,但是不要忘了,在使用UML建模时问问自己为什么要这么做,以及如何用它向下指导生成代码。
早期的软件开发,其错误认识和做法主要表现为忽视软件需求分析的重要性,轻视软件维护,认为软件开发就是写程序并设法使之运行。软件危机的出现让人们意识到项目管理的重要,意识到需求、分析、文档的重要,但同时也导致另一场灾难,即为了文档而文档,为了建模而建模,而忘记了软件开发的最终目的:交付有价值的软件(再往前一步,事实上大部分就是交给编译器的东西——代码)。个人认为,软件开发过程中的一切活动都应该服务于这个目的,否则将只是浪费精力,贻误商机。
看看我们如何用前文所述的方法来指导代码的生成:
我们知道,在OO程序中任何事物都是对象,OO程序的运作就是一系列对象的诞生、死亡,以及对象彼此间的通信。OO将所有对象分成各种对象类,每个对象类定义一组属性和方法。因此OOAD很大程度上就是要找出这些类,为它们定义合理的属性和方法,也就是产生合理粒度的类。其实很多OO新手最大的问题就在这里,一个类包容一切,导致软件的呆板、脆弱、难理解、难以维护、不可复用。
回到上述开发过程。第一步我们将得到好的用例文档,它在一定程度上描述了用户如果使用系统、系统如何响应用户要求以实现用户目标;通过抽取该文档中的名词,经过快速、细致的分析,我们可在第二步得到大多数重要的类,并初步确定类的属性;在第三步,使用顺序图来描述各个对象间如何交互以实现用例,为各个类分配职责,这便可以初步确定类的方法;在此之前得到的结果都是平台无关的,我们可在第四步通过结合具体的平台进行设计,对前面的得到的类进行进一步的精化,此后便可方便的将设计结果转化为代码。
在第三步使用顺序图为类分配职责时应该遵循一个总的原则:低耦合、高内聚。具体地说,应该遵守以下几条原则:
1. 专家原则。把职责分配给信息专家,即那些有足够资源来承担该责任的类。
2. 老板原则。在B聚合或组合A时,发给A的消息应先通过B处理和中转。
3. 可视原则。不要和陌生人说话,两个对象之间有消息交互,相应类之间应该有关联。
三、 使用UML,形势正确容易,内容正确难。
UML、OO在国内也算是风光过好一阵子了,说起来大家都在使用UML,都在OOAD,但真正取得了理想成果的团队好像并不太多。为什么会如此?我很赞同Think的说法:形式正确容易,内容正确难。就拿用例来说,好像大家都是在捕获需求,但是如果包含了太多的细节,那么用例文档就不得不经常的变更,因为细节是容易变的,文档必须和他们同步;如果过分地细化用例,那么必然会犯上将步骤当用例的毛病,这样的“用例”将无法实现用户的一个完整目标,无法为用户创建价值,也便违背了用例的初衷。所以说,对于UML的学习,除了其形式上的东西,还应该多多思考,掌握表面下面的东西。
如果说用例体现了用户的目标,那么其中每一个步骤都应该向这个目标迈进;如果说软件开发是一个问题域到解域的求解过程的话,那么在开发周期中的每一个活动都应该向解域迈进。就像我们从前解方程,不管其中有多少过程,其目的都是为了最终那个结果,阅卷人不会因为你在其中说了半天的废话而给你加上半分;软件开发也是如此,客户也不会因为你在其中走了多少弯路而多掏半分钱给你。过多的形式上的东西,好看不中用的东西,不是自我折磨,便是自我安慰。
说到底,UML本质上是建模语言,其根本目的是辅助求解。简单的、实用的、对求解有帮助的内容,能够帮助开发人员向下生成代码的内容,才是正确的内容。
2003-11-16
参考书籍:
Steve Adolph, Paul Bramble. 有效用例模式
本文地址:http://com.8s8s.com/it/it37018.htm