过程塑造(小型软件团队过程改进方法)
一、从方法到编码
这是一篇偏重于介绍方法学(特别是 Agile 方法)实践的文章。
其读者对象是那些希望在自己的软件团体中引入某个过程方法,但又
不知从何入手的开发人员、项目经理们。本文中所提到的内容更适合
于应用在小型的软件团队中。对于较大规模的软件团队,本文中的部
分内容也适用。 本系列包括: 知识接力、 代码是最终目、 一致性
的思考、 活跃和混乱、严谨和死板、 短期利益和长期利益的权衡。
软件管理和软件开发是截然区分的吗?
对于项目经理来说,其职责是软件项目的管理,而对于架构师、
编码人员来说,其职责是软件设计和开发。虽然在一些小型的团队中,
这两种职责有时候是同一个人担任的,但两种角色的区分是必要的。
从事过软件开发的人都能或多或少的感受到软件管理和软件开发之
间客观存在的沟壑。
我常常听到来自两个方面的声音。一边抱怨说设计师、编程人员
阳奉阴违,难以管束,导致已订立的软件过程形同虚设。另一边抱怨
软件过程存在诸多不恰当的地方,变成了软件开发的绊脚石。
现代的方法学理论以及相应的过程实践为我们奠定了软件开发
科学管理的基础,个中的翘楚包括 RUP 和 XP,纵观这些方法、过程,
都非常强调过程的流畅、生命周期的延续。而在实际的应用中,我们
却常常能够看见对它们的不恰当的理解,不正确的使用。尤其是那些
希望在自己的软件团体中引入新型的方法过程新手们。对于他们来说,
最容易犯的一个错误就是忽视了如何利用一个软件过程来创造一个
成功的软件。
关于如何建立一个软件过程的资料很多,但是这些资料并没有把
为什么需要过程,过程的目的是什么之类的问题说清楚。而这些资料
的读者们,往往需要花费大量的时间,亲自进行实践之后,才能获得
这些问题的答案,而付出的代价是教训和挫折。同样的,我和我的伙
伴们也经历了这样一个过程。因此,我希望把我在过程应用、过程改
造中涉及到的问题例举出来(采用过程模式的方式)。如果大家能够
利用到这些经验(哪怕是一些),那本文的目的也就达到了。因此,
本文并不是一篇专门讨论如何建立过程的文章,也没有涉及建模、设
计、编码等方面的内容。但是本文中所讨论的内容都可以对以上的活
动起到部分的指导作用。
敏捷?敏捷!
从开始研究软件工程,我就对敏捷过程的概念情有独衷,但是随
着学习的深入(所犯错误的增多),我发现敏捷是无处不在的,她是
一种尺度,一种处于"混乱"和"死板"之间的平衡艺术。有句俏皮话说
的是"一放就乱,一管就死",这句话很好的点出了软件过程的一种无
奈性。如果没有严格的规定,软件开发就陷入一种混乱、无序的状态,
但是如果制定了过于严格的规定,软件人员的思路又受到极大的约束,
管理成本也随之上升。敏捷正是一种处于两个极端之间微妙平衡的艺
术。这种艺术难以完全表述,但是可以通过一些指导,来帮助大家达
到这种境界。
因此,我们可以推想的到,敏捷是见仁见智的。每一个软件团体
都有自身的特性,其敏捷过程必然都不尽相同。如何设计出成功的敏
捷过程,来保证软件团体的成功呢?本文通过一些过程模式的讨论,
揭开了问题的一角。关于过程设计的完整的讨论,大家可以参考敏捷
软件开发[Alistair Cockburn]一书(该书近来将有中文版面世),该书
详细的描述了过程设计的来龙去脉,以及如何根据组织的特点来选择
适当的过程。
因此,虽然本文中并没有特别提到敏捷的字眼,但是所讨论的内
容无不在敏捷思维的范围之内。
MDA 推动软件可重用框架的建立
我有一个梦想,希望有一天能够不用在诸多的平台之间摇来摆去。
虽说 Java 语言的口号就是跨平台。但事实上,我们还是无法完全摆
脱平台的束缚。
在 的规范中,提到了一个 MDA(Model Driven
Architecture)的概念。在众多的软件平台中不知该如何选择,已经演
变为当今软件开发的主要难题。MDA 的存在目的就是为了解决这个
问题。通过 MDA 技术,一个 UML 的模型可以是平台无关的,称为
PIM(Platform-Independent Model),也可以是和特定平台相关的,
称为 PSM(Platform-Specific Model)。利用平台技术的软件商,可
以专注于自己的领域,集中描述业务功能,业务规则,而无须考虑特
定的技术,构建出一个 PIM,然后,通过支持 MDA 的工具,将 PIM
转换(通过不同 Profile 进行映射)为一个或多个 PSM。这时候的模
型仍然是 UML 的。但是,这个转换过程虽然有工具的辅助,但仍然
需要外力的介入。接下来,开发工具将会从 PSM 中产生可执行代码。
这就是 MDA 的思路,它把以往以程序为中心的开发模式转变为以设
计为中心的开发模式。
以往的重用,往往是基于代码的,例如算法的重用、界面组件的
重用,却往往没有将重用提升到设计的层次上。MDA 为我们建立可
重用的框架提供了一个很好的指导。注意上面的这副图,最外面的两
层就表达了 MDA 可以用于设计重用的基本理念。倒数第二层的含义
是利用 MDA 来进行通用软件(例如事务、目录服务)的模型设计,
倒数第一层则表示 MDA 可以用于特定业务领域的设计建模。可以想
象,今后软件公司中的最有价值的资产,就是这些设计模型。
本文并不打算详细讨论 MDA,除了简单的介绍 MDA 的思路之
外,更重要的一点是企业可重用框架的建立。软件企业的核心在于知
识,如何有效的将人脑中的知识存储起来,并不断的使用和发展,是
软件企业成功的关键。本文提到的可重用框架,指的就是将软件开发
相关知识存储起来的框架。这个思路是本文的一个核心思路。在本文
看来,可重用框架不但包括了设计模型,还包括了过程和方法。软件
开发是在这个框架之内运作的,同时反过来影响着框架的完善和改进。
过程塑造模式语言
下述的模式都是从软件开发过程中,围绕着可重用框架的建立
整理出来的一些经验,之所以整理为模式的形式,是因为这种方式
有利于类似情况的鉴别和对其进行必要的扩展。在软件开发中会遇
到各种各样的问题,以上模式中讨论到的问题都是我们在实践中,
或是和其他开发团队沟通中反复遇到的。因此坚定了我们将之整理
为模式的信心。目前我们得到的模式并不多,但是随着经验的增加,
我们会得到更多的积累。
本文介绍的模式都比较注重权衡的艺术。我们认为这是敏捷思维
的必然结果。世界上并没有什么绝对的事情,尤其是目前多变的社会
中,昨天的标准并不适合于今天的环境。因此,我们的平衡点也在不
断的变化。
传统、经典、学术的瀑布模型为我们建立了软件开发的基本过程,
虽然有各种新的生命周期模型的提出,但是基本的过程并没有太大的
变化。例如,增强性的瀑布过程是在瀑布模型的基础上增加了回溯到
上一个阶段的能力;迭代式过程的每一次迭代都是一次微小的瀑布生
命周期。在这个生命周期模型中,信息在初始需求收集阶段生成,并
通过分析、设计、编码、部署等阶段转化为用户最终需要的软件。在
这样一个延续性极强的周期中,我们如何保证信息能够得到正确的传
递呢?我们用什么方法来避免信息传递的失真呢?我们如何在这样
一个过程中处理人与人之间的交互呢?在正确传递信息的情况下,我
们又如何保证投入的最小化呢?这些问题正是 知识接力模式所重点
关注的。
我不只一次的见过为过程而关注过程的情况。产生这种结果的一
种原因是“过程麻痹症”。过程一旦定型,就不再改变,即便当初制定
过程的环境已经发生了变化也是如此。过程的制定一定是针对特定的
目标的,这个目标就是开发出成功的软件,如果不能够服务于这个目
标,遵循过程又有什么意义呢?另一种原因是过程被分割为彼此独立
的片断,每个开发人员只关注自己的职责,而忽略了最终的软件。过
程的 代码是最终目的,开发过程中的所有活动都围绕着这一目的而
展开。如果没有最后的用于交付的代码,软件就无法成为软件。因此,
必须保证过程能够产出代码,而且是优秀的代码。
一致性原则是软件开发中重要原则,也是最令人困惑的原则。做
到完全的一致性将会导致高昂的成本,而不一致又会导致项目出现各
种各样的问题。可以想到,这又是一个需要权衡的问题。软件项目中
的一致性大致可以分为两种,一种是不同工件之间的一致性(例如设
计模型中的类名称和实际代码中的类名称的一致性),一种是工件和
软件过程的一致性(类名称需要满足命名标准)。我们如何考虑这两
种情况下的一致性呢?
人们说管理既是科学也是艺术,这句话用来形容软件工程再适合
不过了。如果说这里有什么不够恰当的地方的话,我倒觉得是"软件
工程"的这个提法有些许的欠妥。软件工程的思路源自于人们渴望软
件开发能够像土木工程那样成熟。但是几十年的经验下来,大家可以
肯定,软件开发和土木工程有着太多的不同:开发人员和建筑工人也
有着截然不同的差异,知识的组装和钢筋混凝土更是天差万别。(但
为了保证延续性,我们在本文中仍然延续软件工程的提法。)因此,
软件工程需要在科学和艺术之间求得权衡,科学的一面包括了软件开
发规范、准则、实践、过程、方法;而艺术的一面则囊括了人员的激
励、协调,组织的设计等因素。因此我们需要审视我们的规则、过程、
方法,它们是否能够发挥出人的创新性?或是它是否足以约束人的行
为?这就是 活跃和混乱、严谨和死板模式所要告诉我们的。
应该说,本文中所讨论的模式更适合于使用面向对象技术的开发团队。
尤其是 短期利益和长期利益的权衡模式。和大多数人一样,我们最
早也是过程式编程阵营的一员。在经过长时间的学习和不断的犯错之
后,我们终于转向了面向对象。面向对象最大的好处包括了以下几个
方面:
将实现和接口分离,即把如何做隐藏起来,而把做什么展示给
客户。
继承和多态使得我们能够在一个抽象的层次上(基类和接口)
思考问题,并能够根据现实的需求进行灵活的调整(子类和实
现)。
通过设计模式和设计技巧的应用,可以有效的降低系统的不同
部分之间的耦合度。尤其是简化客户端的代码。
在使用和比较过几种开发语言和开发环境之后,我们发现,其实
最关键的并不是使用什么样的面向对象语言(或环境),关键的是你
运用面向对象思维的能力,或者说对现实世界的理解、抽象、映射的
能力。这种能力决定了你的开发水平的高低,而语言和环境只是一种
重要的实现手段和工具而已。而这种思维能力,虽然可以通过例子和
讨论来进行介绍,但更关键的还是在实践中进行练习。在本文讨论的
模式中,我们会夹带的对这些内容进行讨论。因为我们认为,开发思
想和开发过程是无法区分的,否则,你的开发过程就没有灵魂。这也
是我们的主题所要强调的:从方法到编码,铸造起一个敏捷的、流畅
的过程,才能够保证开发过程的成功,开发软件的成功。
此外,本篇是总论性文章,在撰写此文时,该篇其实是最后完工
的,因此,建议大家在看过全文之后,如果还有耐心,可以重看此篇,
相信会有另外一番收获。
现在请大家进入我们的模式之旅。
二、知识接力
在软件过程中,我们如何保证信息能够得到正确的传递呢?我们
用什么方法来避免信息传递的失真呢?我们如何在这样一个过程中
处理人与人之间的交互呢?在正确传递信息的情况下,我们又如何保
证投入的最小化呢?
1、 意图
软件开发过程是知识传递、知识转换的过程。注重知识转换中的
完整性,保证知识经过各个阶段和活动,顺利的转换为软件是极为重
要的。
2、示例
元朗公司是国内某银行的下属企业。从年初开始,公司就投入了
大量的人力为银行开发新版本的国际收支系统。考虑到这是一个非常
庞大的系统,因此公司把原先的软件开发团队扩大了一倍,补充的人
员有些来自于其它的项目组,有些人员来自别的公司。为了保证开发
的顺利进行,项目经理引入了软件过程。但是从一开始,麻烦的事情
就出现了。项目组中的技术人员和银行的领域专家之间不断出现意见
相左的情况。主要的问题是后加入的员工对目标领域不熟悉,难以配
合领域专家的工作。最糟糕的是,某些领域专家身处异地,因此在需
求分析的中期,开发团队邀请这些异地的领域专家来到开发所在地,
进行了为期两天的讨论会。结果并不理想,讨论会上充满了对原先已
定稿的需求的反对性意见,技术专家、领域专家吵成一团。需求分析
阶段不得不在原先的基础上延长了 50%的时间。在进入设计和编码阶
段之后,问题少了许多。但在设计到编码的过程中仍是出了一些麻烦,
原因是新加入的人员不熟悉开发团队的设计风格。经过一番周折,问
题基本解决了。可等到项目进入到测试阶段,矛盾一下子就凸现出来
了。测试报告指出,软件中存在着大量的问题,大部分的问题都被定
性为无法满足需求的严重错误。经过对错误的复审,排除了其中 17%
的严重错误。经过分析,发现其中 70%的错误都是发生在后加入人员
负责的模块中。而产生大量错误的一个主要原因是在编码阶段,由于
银行启用了新的会计制度,导致大量模块被修改,由于时间紧迫,因
此没有进行正规的需求调研。现在看来,领域专家和技术专家对同一
个问题的理解并不相同。最后,项目的开发周期延长了 40%。
3、 分析
软件过程每经历一个阶段,就会发生一次知识转换的情况。这种
转换是由人来完成的,这就是像是接力一样,一个人把脑中的知识以
某种方式传递给另一个人,再有另一个人传递下去,直至编码人员把
这些知识固化在最终的软件中。在软件成型之前,知识的主要载体是
文档和模型。我们称它们为工件(Artifact)。例如,需求阶段时,领
域专家在技术专家的帮助下,将自己脑中对领域的认识传递给技术人
员,并最终形成需求规格书或是用例模型。而在分析设计阶段,技术
专家借助需求规格书,把脑中对软件的初始认识进一步转换为分析模
型、设计模型、数据模型等工件。最后,在编码阶段,编码人员把这
些工件中隐藏的知识转化为软件的形式。经过测试和部署,软件将会
交付到用户手中。这是非常典型的软件开发过程,再简单的软件开发
也需要经历上述的这些阶段。
可以看到,在上述的软件开发过程中,知识形式发生了两次的重
要转换,知识所属角色也改变了两次。知识完成第一次的形式转换之
后,将成为需求规格书(或同类工件)的形式,知识从领域专家的脑
中转换到技术专家的脑中。然后,知识开始了第二次的形式转换,形
成设计模型(以及同类工件)。随着知识从技术专家转移到编码人员,
知识转换为其最终的软件形式。在这些转换的过程中,最容易出现信
息遗漏、信息失真的情况。保证转换过程中知识的完整性和正确性,
对软件开发具有重要的意义。
4、问题
如果保证转换时知识的完整性和正确性?
5、方法
知识转换的主体是人,因此我们主要的对策也是针对人来展开的。
我们知道,软件过程的特点就是:越早埋下祸根对项目的杀伤力越大。
所以我们首先需要重点防范的对象应该是在初始需求分析阶段。需求
分析阶段涉及的知识非常的多,大家如果有兴趣可以参看我的文章-
需求的实践。但这里我们重点的任务是找出需求分析阶段中发生知识
转移的关键点。
领域专家和技术专家是需求阶段中最重要的两种人,不论你的项
目和团队规模属于哪一种层次,一定都包含这两种角色。如果你的团
队中领域专家和技术专家是同一种人,那么恭喜你,你可以不用阅读
这一段的内容了。可惜在强调分工协作和软件规模不断扩大的今天,
这种人已经非常难找了。领域专家是知识的最初持有者,其职责是为
项目提供准确的、完整的需求信息。技术专家的职责则是帮助领域专
家完成这一项工作。所以,首先请保证领域专家和技术专家是能够沟
通的,示例中的项目的第一个问题就是团队的新成员和领域专家之间
存在沟通壁垒。在我们的经验中,就发生过一位优秀的技术人员和一
位资深的领域专家争吵的事情。剖析原因之后,我们发现,最主要的
原因是他们两个人都太优秀了,技术人员有一定的领域经验,领域专
家有一定的开发经验,这导致了双方在讨论中的强硬立场。因此,如
果遇到类似的情况,请对你的组织进行岗位调整。但在执行这项工作
之前,请小心你的说辞,不要伤害到任何一个人。"我们的某个小组
有麻烦,那边非常需要你的经验和能力"会是一句不错的说辞。其次,
技术专家不应该提出任何可能影响领域专家的问题。只有领域专家才
能够提出需求,技术专家起到的只是辅助作用。因此请杜绝这种情况。
再次,如果你的领域专家不只一个人,那么你需要考虑领域专家之间
可能出现的不一致。为领域团队指定一位领导者是一种不错的做法。
在我们的一个项目中,就曾邀请对方公司的财务总监担任这一角色。
理由有二:1、财务总监具有权威性;2、财务总监了解公司的全部运
作。此外,如果领域专家分布在不同地点的话,你需要在该阶段的某
个时期,安排需求讨论会,并考虑一种能够沟通的方式,以便随时能
够了解身处异地的领域专家的意见。这种情况对于那些拥有分公司的
公司(例如银行、证券、保险、销售公司等等)而言非常的普遍。因
此,我们在需求分析阶段,首先要处理好领域专家和技术专家之间的
关系。应该说,这里提到的内容不仅仅适用于需求阶段,在整个的开
发过程中都有用处。
需求不是实现。需求表示的是有什么(What),并不关心如何
做(How)。如果在需求分析阶段把精力分散到了如何实现需求上,
那么需求分析的效果就会受到影响。这体现在需求的完整性和正确性
两个方面。领域专家和技术专家都可能犯类似的错误。领域专家往往
只能够针对自己的工作来描述需求,而他会很容易的把自己对于需求
实现看法参杂到需求描述中。从项目的整体范围来看,这种需求描述
有时候是有问题的。如果你开发的是一个定制应用,那问题还不大,
如果你开发的是一个产品,那么问题就很严重了。领域专家描述的需
求一定是你需要的内容吗?例如,你打算开发一个配送的管理应用,
但是领域专家把大量的精力花在了他在原先的公司中如何实现配送
的流程上,这个过程可能适合于他的公司,但是对于产品而言,可能
就不合适,因为并非所有的配送公司都使用这种流程的。好吧,你想
要的内容和你不想要的内容混合在一起,这使得你不得不花费精力对
需求进行进一步的整理。因此,好的做法是,一开始就明确领域专家
应该提供什么,而且,尽可能的提供需求,而不是需求实现。多问一
些诸如"如果环境发生变化,你该如何做"之类的问题,否则你会发现,
用户的需求变化将会对你的软件造成很大的影响。再说技术专家,技
术专家常常犯的毛病是把分析参杂到需求调研中来,从需求描述中精
练出一些业务实体(或进行 CRC 讨论)是可以的,但是过早的考虑
实现方式将会限制你的思维。因此,请确保需求只是需求,这样才能
够尽可能保证需求的完整性和正确性。
需求复审是非常重要的检查点。请确保你正确的使用它。需求复
审需要领域专家和技术专家、以及管理者的参与。需求复审是保证需
求完整性和正确性的最后一道防线。在很多的文章(包括我的需求的
实践一文)、过程都对需求复审进行了论述,我们这里就不赘述了。
在实践过程中,我们发现,需求复审还有一个好的方式,为了能够通
过需求复审,需求分析人员(包括领域专家和技术专家)会非常努力
的找出需求中的问题。所以,在你的过程中加入这个检查点是非常有
必要的。
好的,如果这一切都进行顺利的话,最后的需求规格书应该是比
较完美的,而技术专家也已经从领域专家那里了解到了足够的信息,
可以开始下一阶段的开发了。这里,我们再花一些笔墨来讨论迭代过
程中,我们如何处理需求。实践中,我们认为迭代次数并不是越多越
好,应该根据项目规模和团队特点进行区分,每一次的迭代都可能有
自己的目标。例如首次迭代的周期可能比较短,其主要的目标定为提
供软件原型、验证主要设计思路等。第二次的迭代的周期可以长一些,
目标可以定位为实现主要功能。如果软件规模比较大,也可以为每次
迭代设定需求范围(或主要场景),这样就能够防止需求扩散的情况。
这已经超出了本文的范围,因此我们这里只是简单的提一下。
分析阶段是发生职责转换的重要阶段。该阶段的成败对软件开发
至关重要。对于面向对象开发而言,这个过程最主要的任务是对领域
进行建模。比较好的方式是使用 UML 来描述领域知识,例如,我比
较经常使用类图来建立分析模型,使用顺序图来描述动态流程。请确
保技术团队中最出色的分析建模人员参与这个初始分析建模的过程。
他的职责包括指导建模和对模型进行审查。如果在一个迭代过程中,
这个模型是不断演进的,这可以减少一些风险。在这个过程中,建模
人员可以吸收领域知识,这对于后续阶段中指导其他开发人员是很重
要的,对公司的长远目标也具有重要意义(参见 短期利益和长期利
益的权衡模式)。如果建模人员缺少面向对象开发的经验,他会很容
易把对象变成一个数据容器。这种方式并不是不好,但它把数据和行
为区分开来,无法站在一个抽象的高度上对领域进行分析。
很难严格的区分分析阶段和设计阶段,至少我是这么觉得的。他
们的差别仅仅是在分析的详细程度上(有点类似于以往的概要设计和
详细设计)。在实践中,我们发现,并没有必要严格的区分它们,但
是你需要保证模型已经完整的描述了需求。这里可以设置检查点来验
证,也可以在设计模型出来之后再进行检查,这取决于具体的项目。
因此,我们在分析阶段和设计阶段结束之前需要进行设计复审。
从 Martin Fowler 提出分析模式的概念之后(现在他的第二本分
析模式正在写作中),它就成为分析建模的有利助手之一--对领域
概念进行分析和建模,并描述它们之间的关系(我在点空间上的一篇
读书笔记反应了需求和分析之间的关系)。但是请千万注意,不要误
用和滥用分析模式。因为任何分析模式的提出,都是基于某个上下文
环境中的需求的,如果上下文环境不同,那么模式就需要改进或改造。
因此,分析模式是一个好的开始,但需要你针对实际需求具体分析。
在应用模式方面,Frank Buschmann 的 Applying Patterns 是一篇不错
的参考文章,其中文版发布在点空间上。
请按照逐步精化(迭代)的方式来完善、改进你的分析模型。优
秀的设计一定不会过于复杂。如果你的分析模型出现过于复杂的情况,
到处充斥着复杂的关系网。那么,你需要对你的设计进行结构上的改
进。例如,采用分层(参见 敏捷架构设计一文中的分层模式)、组
件技术、或是使用单向联系。坚持这一过程,你会发现最后的设计是
简洁的、完美的。
在设计阶段,要注意的事项和分析阶段相差不多,例如不要误用
和滥用设计模式。但是有一点是需要额外强调的。当分析模型已经能
够完整、正确的描述需求之后,我们就需要在设计模型中添加设计资
料。例如对包、组件、类、方法的描述。这时候,需求的信息已经被
打散到软件的各个部分中了。而设计模型在被实现时,设计模型中的
信息又将进入到代码中。因此,保持这些信息的一致性就显得非常的
关键。而由于设计模型处在中间地带,它的重要性又是不言而喻的。
基本的处理思路分为两步:在需求发生改变时,请同步更改设计模型
以及设计模型中的信息。再由设计模型驱动代码的修改。第一个步骤
是需要手动实现的,但是第二个步骤可以由计算机辅助实现,即保持
设计模型和代码信息的一致性(将在 一致性的思考模式中讨论)。
目前有很多的建模工具都可以做到这一点,甚至能够实现产生最终
的 API 文档。善用这项功能,它能令你事半功倍。
在软件过程中设立反馈活动,可以有效的减少项目的偏差。就像
我们骑自行车,很少能够走一条直线,一般我们是根据对目标的偏差
进行忽左忽右的调整。这就是反馈的机理。原型法是一种不错的反馈
机制,根据我们的经验,视觉刺激对用户是最为关键的,因此不论你
的需求文档做的如何的优秀,仍然比不上一个能够看得见的软件原型
有效。这一实践很多的软件工程资料中都有叙述,我们就不深入了解
了。另一种反馈机制是渐进交付。把软件产品分为多个迭代周期,每
个周期交付一个可运行的软件,在获得用户的反馈意见之后,在下一
个迭代周期进行改进,最后一个迭代周期交付的就是完整的软件了。
6、对可重用框架的改进
在找到了适合软件企业自身的知识接力方法之后,应当将其作为
规范或指导意见,加入到现有的软件过程中。例如,在需求分析完成
之后强制要求进行需求评审。加入到过程中的方法,小心不要流于形
式。这样,既付出了成本,又收不到应用的效果。使用工具也是保持
知识顺利交接的重要方法。例如,采用自动产生源代码的工具,模型
设计工具、帮助产生工具、对象-关系映射工具等等。如果这些工具
对你的过程起到了润滑的作用,请规范和普及工具的使用。
7、小结
请确保领域专家和技术专家之间的顺畅沟通。
完整、准确的描述需求。
进行需求复审和设计复审。
保证分析模型(设计模型)能够完整的描述需求。
保持需求信息到设计信息到代码注释的一致。
使用反馈机制。
三、代码是最终目
过程的最终目的是代码,开发过程中的所有活动都围绕着这一目
的而展开。如果没有最后的用于交付的代码,软件就无法成为软件。
因此,必须保证过程能够产出代码,而且是优秀的代码。
1、意图
无论哪一种过程,其最终目的都是为了产生出可执行、并且可用
的软件。因此软件过程中的各种活动应该围绕着快速、准确的实现这
一目的而展开的。
2、示例
维力亚软件公司是一家合资公司,由于有外资背景,公司内部很
早就引入了软件工程,并严格的对人员角色进行分工。包括领域建模
人员、架构设计师、高级程序员、程序员、界面设计师等等多种角色。
每个人各司其职,充分发挥出了分工的特点。但是随着公司开发项目
的逐渐增多,这种方式也显露出其弊端来。每个人的主要目标都是为
了通过评审,而有时候,就算是通过评审的工件,依然可能存在问题。
但这时候扯皮就出现了。项目中存在的一些中空地带。以及交错地带,
常常发生无人问津的情况。开发过程的效率开始下降,开发成本开始
上升。问题虽然不是一下子出现的,但是已经逐渐变得严重起来了。
3、分析
我们在进行过程设计,或引入一个过程理论的时候,有没有思考
过该过程的每一个阶段、每一个活动的目的是什么,它们对生成最后
的软件有什么样的帮助,这些帮助对于我们所在的组织有意义吗。很
多情况下,我们并没有这么做,或者随着软件过程的定型,就不再思
考这类的问题。一开始并没有什么了不起的,但是当软件过程演变成
了一种政治体系的时候,那么问题就会慢慢严重起来。
4、问题
如何让过程围绕着产出软件的核心目标而不断演进?
5、方法
从上一篇介绍的内容中,我们知道软件过程的每一个阶段都是知
识转换的过程,知识转换的终点就是软件。问题在于,我们如何保证
这种转换的效率呢?
现代软件的发展的趋势是重用。我们开发一个软件已经很少会从
最底层开始编写了。我们使用各种各样的技术和平台。包括数据库、
分布式体系、UI 机制、业务元素等等。因此现在的软件编写往往都
是站在巨人的肩膀上开始的。不同的软件组织,肩膀的高低也不一样。
比如有的软件组织使用 J2EE 平台,有的软件组织则使用.NET 平台。
但是可以肯定的一点是,每个软件组织都或多或少的拥有自己的平台
体系开发经验。这些经验的表现形式也不尽相同,可能是保存在某些
高级技术人员的脑中,也可能是保存为文档、模型或代码的形式。
对于单个的项目而言,其过程一定是从需求开始,以部署(以及
后续维护)为终结的。但是对于长时间存在的软件组织而言,更重要
的是项目经验、技术经验、管理经验的积累。这样说可能过于抽象,
我们举一个具体的例子。在完成了一个库存管理项目之后,我们把库
存管理的领域知识制作为商业组件的形式,而把项目中学习到的一些
编码的技巧整理为模式的形式,并把项目过程中积累的过程方法添加
到现有的软件过程中。这些经验的堆积就是在一开始我们提出的可重
用框架。对一个软件团队的来说,它的所有软件项目都应该是围绕着
这一个可重用框架而展开的。
迄今为止,我们见过的大多数的可重用框架表现形式都可以总结
为:以开发平台为基础,积累自己的商业组件,并以此为中心订立开
发活动。这种形式是不是最好并没有定论,但我们是抱着学习的态度
来研究它的。
以开发平台为基础的意思是软件组织必须有自己所熟悉的开发
平台,其大部分的项目都是在此基础上进行的。目前最流行的两种软
件开发平台是 J2EE 和.NET,但是就算是同一个平台,不同的软件组
织对平台内部的侧重也是不同的(同样对于 J2EE 技术,有的软件组
织可能把 JSP 和 Servlet 作为核心选择,而另一些软件组织则把重点
放在 EJB 上)。选择一种广泛应用的、具有生命力的平台技术是非
常重要的。因为你的框架将会以此为基础进行,而框架的转移成本是
非常之高的。虽然我们在一开始介绍的 MDA 思路为我们绘制了一副
平台无关设计的美好愿景,但是在目前阶段,我们仍然要面对不同软
件平台造成的严重隔阂。
必须指出的是,我们上面提到的开发平台指的是在操作系统这个
层次之上的平台,也就是俗称的中间件平台。但是从中间件到最终的
产品之间有没有过渡的平台呢。其实可重用框架就扮演了这一角色。
软件市场上已经出现了商业化的可重用框架了。IBM 的 SanFrancisco
框架就是这种概念的代表。
平台技术仅仅只是提供了一个技术,而软件组织要生存和发展,
还需要积累和发展自己的商业组件。并将商业组件发展成为可重用框
架。商业组件的好坏,直接和软件组织的能力、经验,以及平台技术
相关。商业组件可能直接表现为代码的形式(Bean、类、COM 组件
等),也可能只是描述性的记录(文档)。商业组件是经验积累而成
的。请注意,商业组件的设计并不完全等同于面向对象开发,因为面
向对象只是一种技术手段,但是商业组件设计的优劣,更重要的是对
业务的理解程度。举一个最浅显的例子,一个精通面向对象开发、面
向组件开发的设计师,让他介入他完全不了解的行业组件设计,他的
表现将会大打折扣。
到目前为之,大家所认识的框架仍然是技术型的框架。但事实并
非如此,框架还包括了外延的一系列软件活动。这才是一个完整的框
架。结合之前我们讨论的软件交付为开发目标。我们把这种开发方式
称为以可重用框架为核心,以交付为目标的软件开发。这其实并不是
什么了不起的概念,大部分的软件组织都已经这么做了,只是没有意
识到自己的方式而已。了解这一点,能够帮助软件组织有效的改进自
身的构架。
平台技术和组件开发并不是本文的重点,因此我们在肯定了两者
的重要性之后,把精力转移到软件活动上。
在拥有一个框架核心(平台和商业组件)之后,框架需要包含这
样的活动(或活动集):收集项目需求,并将需求映射到核心构架上
来。这其实就是需求阶段到设计阶段要做的事情。但是由于我们的活
动是以软件交付为目标的,因此我们需要明确的指出活动中的注意事
项。
为映射工作设计需求描述规格。需求并不是一件容易的事。最
难的莫过于尺度的把握了,例如需求要多详细。使用现成的技
术来定义需求描述规格,并根据核心框架的特点进行必要的扩
展。例如,我们使用成熟的用例技术来描述需求,同时我们要
求需求按照不同类的商业组件进行分类索引。用例技术的推荐
读物是 Alistair Cockburn 的 Writing Effective Use Cases 一书,
该书目前已有英文影印版。
保证需求规格能够被项目成员所理解。这里的项目成员包括客
户、领域专家、需求调研者、分析模型设计师。只有他们了解
需求,才能够保证信息的正确的传递。(参见 知识接力模
式)。
为实现需求制定分析(设计)规则和指南 。这是把需求映射到
核心构架上的重要步骤。制定规则是必要的,但要小心,不要
让规则限制住开发人员的创造力(参见 活跃和混乱、严谨和死
板模式)。规则的形式可能是设计规范、分析模式、类库、组
件重用等等。在指南中提供示例,描述如何将需求转换为设计
模型是一种不错的做法。同样好的做法还包括了模式指南。
确保测试贯穿了需求模型和设计模型。我们终于提到了测试。
测试在软件过程中扮演着重要的角色。但遗憾的是在本文中直
接提到的机会并不多,从某个角度上看。 知识接力模式中提到
的复审其实也算是一种测试。测试的信息都包含在需求模型和
设计模型之中,例如前置条件和后置条件。在完成需求模型和
设计模型时同步完成测试用例是一种非常好的做法(我们的团
队正是采用这种做法),但是需要小心文档一致性(参见 一致
性的思考模式)的所需要付出的额外成本。
如同在 知识接力模式中提到的那样,让领域专家、架构师和高
级开发人员对需求模型和设计模型进行复审。
原型方法能够有效的帮助最终软件的成功。所谓原型方法,就是
选取系统的某个部分(最直接或风险最高的部分,通常是界面原
型), 实现并呈现给用户,以获得反馈,为后续的活动提供指导。
原型方法最大的好处是能够帮助用户认识软件,消除用户的疑虑,并
发掘潜藏的需求。围绕着是否抛弃原型这一根本问题,原型方法可以
分为渐进原型方法和舍弃型原型方法。前者是在一个软件原型的基础
上不断的演进,并最终发展为可用的软件,后者则是在开发出原型之
后就将它舍弃。渐进原型方法充分利用了原型,但是由于缺乏前期设
计,可能会导致最终产品存在性能或设计问题。舍弃型原型克服了这
个问题,但是它浪费了原型开发的那段时间。不论采用何种方法,最
重要的是在项目一开始就决定采用哪一种原型方法。模棱两可的使用
两种方法是兵家大忌。最终你无法利用任何一种方法的优点,而所有
的缺点都将降临到你身上。相较而言,渐进型原型方法更适合于应用
在小型项目上,因为项目并不复杂的话,设计的改进比较容易。对于
一个拥有构架的团队而言,把原型方法纳入构架之中是很有意义的。
如果构架足够成数,迅速开发出一个原型并不是什么很困难的事情。
这样就可以在投入最小化的情况下获得原型方法的优势。如果情况是
这样的话,舍弃型原型方法似乎更适合一些。
在 知识接力模式中,我们简要的提到了设计模型信息和代码信
息的转换问题。使用建模工具来自动从设计模型抽取信息,并生成项
目的代码。这种方法能够大幅度的提高软件开发效率,并对软件的最
终交付有很大的帮助。同样,将代码中的信息转回到设计模型中(属
于反向工程的一部分)也是有意义的。如果缺少这样的工具,那么请
人为的保证信息的同步,当然,并没有必要保持实时的同步(参见
一致性的思考模式)。
软件的成功和测试活动是无法区分的。我们前面简单的讨论过测
试信息是来源于需求的。测试信息随着需求模型的生成而生成,并通
过设计模型进行转换,在软件过程进入到实现阶段时,测试信息最终
被转变为单元测试用例的形式。单元测试用例可能是针对单个方法的
单个用例,也可能是针对某个开发包的几组用例。我们需要注意两点,
首先是在软件过程中保证这个流程的顺畅和正确。就像在 知识接力
模式中讨论的那样,正确、完整的信息传递保证了最终软件的成功出
产,测试信息的成功传递保证了最终软件的可用性。测试是软件的保
证。因此,我们需要几个活动来保证测试信息的成功:
从需求模型中生成接受测试。该活动把需求映射到测试上。在
这个活动中,不但要注意功能性需求(如完成的功能),还需
要注意非功能性需求(性能要求)。同样的,接受测试也需要
接受复审。可以按照需求的组织方式来组织接受测试。
设计模型完成之后,接受测试已经细化到模型的各个元素上了
(例如包、类)。该项活动和将需求映射到设计的活动是同步
进行的。因为它们处理的信息是非常类似的。和接受测试一样,
这两个活动都需要由团队来保证。
在进入编码阶段之后,开发人员根据接受测试和设计模型,将
会为自己负责的部分设计编写单元测试。单元测试的编写顺序
是否优先于编码,这取决于各人的看法。关于这方面的讨论,
可以参看 XP 的单元测试实践。从我个人的经验来看,先写单
元测试,再写代码不失为一个很好的办法,另一种做法是,让
两个紧密合作的开发人员相互为对方编写单元测试。
其次,我们需要保证测试的最小单元-单元测试的成功。所谓皮
之不存,毛将焉附。单元测试没有组织好,最后的软件是不会成功的:
需要注意单元测试的覆盖率。这里的覆盖率指的是是否能够完
全检测出错误所在。比如边界条件的测试等。开发团队中的架
构师之类的角色需要为此负责,如果无法检查所有的单元测试,
那么可以进行抽查和代码复审会议的形式。后者是一种很优秀
的做法。从代码中抽取出一段,开发人员一起分析单元测试存
在哪些问题,会使得大家编写单元测试的功力不断的增长。
单元测试一定要是自动化的。Junit 就是一个不错的自动化测试
框架。保证单元测试的自动化,并且避免单元测试和特定环境
相关,这样就可以顺利的进行回归测试。这对于迭代式的软件
开发是非常必要的。同时,我们也应该认识到,单元测试的稳
定性取决于设计的稳定性。我们可以想象,如果测试的类方法
的参数、命名都发生改变,那么测试是肯定需要重新组织的。
所以,面向对象的抽象思维对于现代软件开发而言是费产重要
的。为了做到测试的自动化,尽量避免将逻辑硬编码在界面中,
并小心的处理数据库。可以尝试着建立测试数据库。
如果测试的内容需要并入核心构架,那么这部分的测试工作需
要增加,并对构架可能的修改进行测试。因此,学习开源软件
的做法,将构架的稳定版本和开发版本相区分是比较保险的。
让测试活动随着软件开发的进行而进行,让测试活动贯穿整个开
发周期。这有点类似于全面质量管理的思想。因为软件开发过程的失
败并不是突然而至的,而是在平时的不经意间一点一点的积累起来的。
使用测试活动来消除这种微小的不稳定性,能够大幅度的提高最终软
件的质量。但是,在一个团队中引入正规的。频繁的测试活动是需要
耐心的。可以先从单元测试着手,慢慢的普及这种做法。
测试活动可以衍生为日创建和冒烟测试。对于有复数的开发人员
参与的软件项目,就无法避免正视集成测试的局面。有过类似经验的
人都可以想象的到这种集成测试的难度。专门有一句话是描述这种局
面的:"我们已经花了 90%的时间来完成 90%的软件,但我们还需要
90%的时间来完成剩下的 10%"。现代的软件往往都包括成百上千的
文件,这些文件的编译链接的过程是很复杂的。而日创建的思想就是
每天进行一次这样的过程,形成一个可执行文件。但这只是日创建第
一部分内容。日创建还需要对软件进行冒烟测试,测试的主要内容就
是单元测试中所编写的内容,保证软件可以通过所有的测试。
日创建需要留下一些调试的时间,尤其是在软件开发初期,不同
开发人员的代码整合在一起出现问题的可能性极大。随着对这项实践
的熟悉程度,问题会逐渐减少。日创建可以很明显的提高产品质量,
以及提升团队的士气。虽然日创建活动需要付出额外的一些成本,但
是相对于集成测试的不可控,这些成本还是值得的。
6、小结
投资于框架能够保证软件开发的成功。
应用有效的实践活动来完善框架。
将需求映射到核心框架上来。
使用原型法。
注意测试活动。
如果可能,使用日创建,并进行冒烟测试。
规则不同于指南。规则是目标受众所必须遵守的,而指南是建议目标
受众遵守的。
四、一致性的思考
一致性原则是软件开发中重要原则,也是最令人困惑的原则。做
到完全的一致性将会导致高昂的成本,而不一致又会导致项目出现各
种各样的问题。可以想到,这又是一个需要权衡的问题。
1、意图
软件过程中的大部分工件都需要保持其相互之间的一致性。可是,
工件越多,保持一致性的开销也就越大。我们需要在一致性和成本之
间保持平衡。
2、示例
天利软件公司的项目经理正在为开发过程中出现的大量的不一致
问题头疼不已。从软件过程一开始的需求阶段,版本问题就一直困扰
着项目组的成员。项目组的成员并非没有经验,只是这一次的项目规
模超过了以往的项目,因此公司决定采用严格的过程,以保证软件质
量。开发过程中每个活动都必须产出文档。第一次的不一致发生在需
求调研中期的一次研讨会上,当时的会议上发现了三种不同版本的需
求规格书。之后情况越来越糟,文档的数量不断增多,由于所有的开
发人员都需要编写文档、使用文档,因此发生了各种原先没有料到的
事情,包括新文档被覆盖;设计人员手中的需求规格书不是最新的版
本;设计书变更之后,代码却没有相应的变更;代码中的方法说明和
设计模型中的方法说明不一致。为了对文档进行控制,公司不得不从
项目组中抽调了两名开发人员来控制文档,并加强了文档的管理。但
是随之而来的是开发周期的延长。
3、分析
一致性包括两个方面:一是不同工件之间的一致性,二是使用
同样的方法来处理问题。
软件过程的每个阶段都需要产出不同的工件。典型的例如需求分
析阶段将产出需求规格书、用例模型、非功能需求等,设计阶段产出
设计模型、类图。而在软件开发中,我们常常会遇到需求的变更的情
况,因此我们需要依次对我们的需求模型、分析模型、设计模型、代
码进行修改,以保持它们之间的一致性。如果项目处于前期阶段,这
种修改量并不大,因为工件较少,如果项目进行到后期。需求的改变
将会涉及到大量的工件。对于期限比较紧张的项目而言(这似乎是所
有项目共同的特征),这种成本几乎是无法接受的。
另一方面,在同一个软件组织中,解决同样的问题有着不同的办
法。不同的人有着不同的编码习惯、不同的目录组织方式、不同的类
库、不同的框架。虽然我们并不反对同一问题的不同解法,但是当这
种情况对项目的进展起到负面的效果的时候,我们就有必要来思考这
个问题了。
4、问题
我们如何在一致性和一致性带来的成本之间做好平衡?我们如何
保证不同工件之间的一致性,又该如何保证项目中解决方法的一致性。
5、方法
首先,我们应该肯定,一致性这个问题并没有标准的答案。不同
的项目对一致性有着不同的要求。对于要求严格、规模庞大、涉及到
一些重要领域的项目来说,一致性的要求是极为严格的。而对于一个
小型的、较为无关紧要的项目来说,一致性的要求就低了许多。因此,
和前面介绍的模式类似的,一致性的正确的答案只能够从读者自己的
项目中去寻找。而这里提供的,是寻找该项标准的建议。
我们先从后者-解决方法一致性入手。
和这个标准答案相关的是一致性的程度。一致性的标准可大可小。
大的标准包括了设计原则、软件架构;小的标准包括用例的书写格
式、设计模型的注释格式等等。由于大的标准对开发过程的作用最
大,因此在进行一致性处理的时候,应该先从大的标准入手。在 代
码是最终目的模式中,我们提到了构架的概念。以构架为中心来制
定标准,保证一致性是一种自然的思路。核心构架应该要能够确定
软件开发的方向,这样可以最有效的保证一致性,但是不要涉及到
过于具体的细节,除非你对它们已经有足够的经验。而标准的深入
程度则要取决于组织经验、已有的软件过程、项目规模等因素。
对于项目来说,一致性存在一个逐步精化的过程。正如我们上面
所讲的,一开始最重要的是引入核心原则,这里我们认为是可重用框
架。对于可重用框架中已经明确确立的事项,必需要严格的遵守,因
为框架中的内容是足够稳定的,已经经过验证的。这其实是重用思想
的一种衍生。我们在 短期利益和长期利益的权衡模式中还会谈到。
如果有必要,引入的核心原则需要针对项目进行部分调整。例如,框
架中根据项目的规模大小定义了用例的三种写作模板,在项目开始的
时候,我们会选择其中最接近的一种模板,并根据项目增删模板中的
一些元素。而对于框架中不曾定义的,一些尚未明晰的事件,我们在
项目初期不需要进行过于详细的处理,而是随着项目的进展来慢慢的
完善它。例如,由于需求没有确定,我们并不知道最后的设计模型是
什么样的,因此我们先根据框架定义,选择 JSP 和 Servelet 作为主要
的技术基础,由 JSP 负责提供视图,由 Servelet 提供业务逻辑。其它
的信息则等待进一步的精化。
在项目一开始的时候,不要过分注意工件的修饰。例如,我们选
择的用例模板要求每一个用例都需要包括 6 种元素,包括主要角色、
级别、前置条件、主要流程、备选流程、优先级。并规定引用其它用
例的地方需要做出链接。但是在一开始需求调研的时候就按照这种标
准完善用例将会提高成本,因为需求尚未稳定,我们主要的工作是尽
可能完整的收集用例,而不是把时间花费在修饰用例上。因此一开始
任何形式的用例描述都是允许的。你可以使用几句话来描述用例(事
实上,利用自然语言来描述用例有着图形无法比拟的优势),并用着
重号标记出其中可能和其它用例相关联的词汇。这样就已经足够了,
修饰的工作可以等到下一步来做。其它的工件也是一样的。这时候的
一致性的要求并不十分严格。
我们需要注意一些关键点(检查点),例如在 知识接力模式中
提到的需求复审。在项目接近这个关键点的时候,用例应该是已经根
据要求整理完毕,可以接受复审了。粗糙的工件能够迅速的创建,但
是不容易让人理解,也违背了一致性。因此我们虽然可以延迟工件的
精化,但是这个工作是不可以缺少的,当然,精化的程度是可以变化
的。利用关键点来保证工件的一致性也保证了信息传递的一致性(参
见 知识接力模式)。
因此,我们应该根据项目进行的不同时期来保证工件的一致性。
例如,在实现阶段的初期,设计尚未定性,花费大量的时间在设计文
档上就没有什么必要,只需要准备一份草稿,在设计的时候随手记录
下设计思路就可以了。注意,不要不做任何记录,人的记忆是最不可
靠的,过目不忘只出现在小说中。而当项目逐渐成数的时候,我们就
可以为其中成熟的设计进行文档化的工作了。这些可以根据需要发布
给用户,也可以整合到构架中。
再来看第一个问题,如何保证不同工件之间的一致性。
同时维护 3 个工件的工作量,要比同时维护 10 个工件的工作量
小的多。因此,我们应该尽可能的减少在每个关键点中需要保证一致
性的工件数量。同时,我们需要区分,哪一些工件属于必须保持一致
性的工件,哪些属于不需要随时更新的工件。例如,我们在需求分析
中使用了 CRC 卡片,但是它的主要目的是为了顺利的进行沟通,并
得到基本的分析类。这样的工件,保持它的一致性并没有太大的意义。
这种思路类似于 CMM 中的 KPI 的思路,从软件开发过程中找出关键
的工件,把有限的力量投入到保持这些关键工件的一致性上。虽然一
致性狂热者未必认同这种做法,但是对于一个软件组织来说,最重要
的是在有限的资源下的尽量提高软件开发能力。
在构架中包括一系列指南,来指导工件一致性是有必要的。较好
的做法是结合知识接力模式中的知识传递指南。例如,指导如何从需
求说明书中提炼出接受测试和设计模型,这个过程本身就是保持一致
性的过程。同时,光有书面的指导也是不够的,项目进行中,架构师
之类的角色需要对开发人员进行指导(一对一的形式是最佳的)。这
一点我们下文还会提到。
为一致性使用工具有时候也是很有必要的。例如,我们在 知识
接力模式中就提到使用建模工具来保持设计模型和代码中信息的一
致性。这里我们再次强调这一点,因为根据我们的经验,这种做法对
于软件项目是非常重要的。因为设计是很难能够一开始就达到目标的,
它需要不断的改进,而项目的最终期限决定我们不可能等到设计已经
尽善尽美之后才开始编码。因此设计过程和编码过程一定是反复进行
的。重构不断的发生 。我们需要不断的修改设计模型,而此时的设
计模型和代码的信息的不一致就成为主要的矛盾了。一方面它延长了
重构的时间,另一方面,它使得开发人员无法把精力集中在设计上。
如果能够有工具来自动的完成这项工作,将会极大的提高生产率。
另一种工具是版本控制系统,是否使用版本控制系统和项目大小
无关。再小的项目同样存在着版本问题,只是严重程度不同而已。因
此将工件纳入到版本控制系统中来是较好的做法。对于小型的项目而
言,并没有必要限制权限,但对于大一些的项目权限控制就有必要了。
一致性的组织保证
首先,如果不进行任何的管理,项目一定是不一致的。这和人的
基因有关系。因此我们需要为一致性制定专门的人选。例如,需求的
一致性应该由架构师和领域专家负责,模型的一致性由开发人员负责。
但是最终需要一位总的负责人,他负责所有工件的一致性,包括技术
和领域两方面,并决定是否将项目中的经验并入构架中。
不要让一致性为难你的开发人员。一致性是很容易滥用的,因此
请确保正确的使用了它们。例如,制定缩进或留白之类的一致性标准
并没有太大的意义,因为它的成本远远超出了它的意义,并且会遭到
开发人员的严重反对。另外的例子包括过于严苛的编码规则、以及模
式的滥用。这些都是经常会犯的错误。它并不会带来生产率的上升,
只会另开发人员反感。避免它们的办法是,在制定一致性规则之前,
先思考,该条规则的成本是否大过它的利益,开发人员是否愿意接受。
一旦定义了一致性规则之后,就需要进行培训。最好是通过例子
来开始。例如,教授新的模式。如果你进行类似的培训,你就会发现,
把正式的培训和非正式的指导相结合是很好的做法。因此,我们往往
习惯把培训课程分为理论培训和实践两个部分。实践可以安排在课程
结束就开始,也可以安排在项目进行中。
最后,一致性规则需要在整个开发过程中被不择不扣的执行。这
是必须的。此外,还需要评估一致性规则的实际运作情况,如果有不
充分或是不完善的情况,则需要改进它。如果效果不佳,则要考虑废
除该规则。
6、小结
使用构架来保证大原则的一致性。
在事情未确定之前,工件可以是不一致的,但是在关键点时,
工件必须是一致的。
尽量减少需要保持一致性的工件数量。
使用工具来维护一致性。
指定一致性的负责人。
一致性规则必须合理。
严格执行一致性,并根据实际情况改进一致性规则。
五、活跃和混乱、严谨和死板
软件工程需要在科学和艺术之间求得权衡,科学的一面包括了软
件开发规范、准则、实践、过程、方法;而艺术的一面则囊括了人员
的激励、协调,组织的设计等因素。因此我们需要审视我们的规则、
过程、方法,它们是否能够发挥出人的创新性?或是它是否足以约束
人的行为?
1、意图
对开发人员的行为进行约束是必要的,但同时却限制了开发人员
的创意。我们如何在这两的极端之间取得平衡呢?
2、示例
成达公司在以往的项目开发中,一般都不限制开发人员的行为,
公司中开发人员都有各自的编码习惯,使用不同的开发工具,更不用
说遵循什么开发过程了。因此一旦有人员离职,接手的人员往往都需
要花费大力气来熟悉原先的系统,因为原先的人员几乎没有留下文档,
或是仅有一些旧的、不能使用的文档。公司中也有软件人员向管理者
提出过这方面的建议。但是由于软件开发并不是公司的主要盈利机构,
公司不太注重这件事。因此这种情况就一直保持下去。由于公司中的
软件人员大多数都有着多年的开发经验,所以日常的运作也算是基本
正常。从今年开始,情况发生了改变,由于经营策略的改变,公司换
了一位老总,新老总对软件部门非常重视,并投入资金,为软件部分
引入了一套严格的规定,制定了统一的编码规则、开发环境,严格的
作息制度、汇报机制。有位员工这样形容新过程,"就差没有制定上
洗手间的时间了"。过程实施以来,员工怨声不断,由于个人原先熟
悉的开发方式被打破,软件开发速度大大降低。客户的投诉也明显增
加,甚至出现了项目中止的情况。过程实施 6 个月之后,发生了 3 位
资深的开发人员离职的事件。最后,管理层不得不废除新过程,回到
原先的开发方式上去。
3、分析
开发过程有两种极端。我们可以看看下面的两种情况,你更愿意
在哪一种环境中工作。
项目组的三个程序员分别开发项目的三个模块。需求仅仅持续
了 3 天的时间。原定计划是 1 周,但是因为项目甲方人手紧缺,调走
了需求调研的领域专家。三个程序员闷头开发,彼此隔绝。每位程序
员都有自己的类库和开发包。没有文档,没有测试用例。突然,程序
员甲喊道,"昨天我放在这里的需求说明书呢?就是那张上头有脚印
的打印纸。"界面开发一半之后,用户发现似乎不同模块的界面相差
极大,按钮的位置、菜单风格、窗口布局,没有一处相同的。更为糟
糕的是,似乎程序员对用户需求的理解又错了。
程序员乙正在嘀嘀咕咕的修改他的代码,因为架构师在检查了他
的代码之后,指出了 100 多处和标准规则不一致的地方。包括变量命
名、注释规则等等。"烦死了!"程序员丙伸了个懒腰,他正在修饰他
的设计类图。上次也是这样,模型已经画的尽善尽美了,结果又因为
设计发生变化不得不重来一次。看来今天有没什么时间写代码了。项
目经理正在审查昨天各个开发小组提交上来的文档,"这几份文档的
格式都有问题!"他皱了皱眉头,看来在下午的例会上,他还要着重
强调统一规格的问题。
3、问题
可以看到,上述的两种情形正是我们的模式名称的后半部分所描
述的:混乱和死板。那么,我们如何达成模式名称的前半部分-活跃
而且严谨呢?
4、方法
这又是一个需要权衡的问题。正是这种问题让人头疼不已。造成
软件过程无效或束缚开发人员的结果有两种不同来源的因素。一是在
过程选择和创建的时候,我们忽略了一些问题,一种是过程实施后的
控制上我们没有仔细的思考。
软件过程的迷思
很明显的,上面所讨论的两种极端都不是优秀的软件过程。
然而,就像我们看寓言故事一样,在取笑寓言故事中的人物的时候,
可曾想过自己也犯过类似的错误,只是轻重程度不同而已。虽然我
们不会犯上例中所有的错误,但是确实会出现其中的一些情形。那
么,我们在建立软件过程的时候,如何防止出现上述的一些情境呢?
以我们自己为例子。在建立过程的时候,我们选择是以 RUP 为
基础。为什么不选择 XP 之类的敏捷方法呢?原因有二:i)敏捷方法
的实践很优秀,但是作为完整的过程,它仍然有其不充分的地方。
ii)XP 中有很多优秀的实践,但另一些我们并不完全赞同。在选择了
RUP 之后,为了保证过程的灵活,我们删减了大量的活动和工件,
仅保留了一些关键的。但是我们清楚,如果现有的团队规模发生变化,
删除的这些活动和工件可能需要重新添加到过程中来。此外,我们引
入了 XP 中的一些优秀的实践。例如测试优先、重构和结对编程。对
于结对编程这项实践,我们没有完全采纳 XP 的建议,而是在一些关
键的活动上,例如指导、模块设计、单元测试,采用了结对编程实践。
好的,首先,在阅读了这个例子之后,我希望大家不要都去选
择 RUP 或是 XP,这样的话说明你并没有领会这个例子的意思。根据
自己的特色来选择软件过程是这个例子所要表达的第一个意思。有些
团队原先就已经拥有运作的差强人意的过程,因此并没有必要一股脑
转换到 RUP 或是 XP 上去。Alistair Cockburn 在他的敏捷软件开发
(该书已有中文译本,Alistair Cockburn 的网站上有英文原版的草稿
可供下载)一书中讨论了如何根据软件团队选择敏捷过程。事实正是
如此,在开发性命攸关的系统时(例如急救系统),被认为是快餐式
的实践活动,在开发业务系统时,可能就显得过于死板了。因此,在
我们选用 RUP 的同时,删除了其中的很多活动,因为我们不需要它
们。例子要表达的第二个意思是,请选用一个现成的软件过程,而不
是自己开发一个。现成的软件过程往往都经过精心的设计和实践的验
证,而且,如今的大部分软件过程都可以对其进行剪裁,不至于说找
不到完全不合适的过程。其实,例子中还隐含了第三个意思,以往合
适的过程未必就适合现在的情况。在 代码是最终目的模式中的例子
吗?没有永远合用的过程,让你的过程随着你的组织的成长而成长,
随着环境的变化而变化。
不要过于在乎你的过程过轻或过重,只需要关注它是否合适,开
发人员能否接受。新的过程是否要求开发人员改变原先的习惯,而他
们的反应如何?很多时候,正是对旧习惯的挑战导致了开发过程的失
败或不顺利。这里需要非常小心的处理。
在引入软件过程的时候,不要花费大量的时间来编写描述过程的
文档,尽量利用现成的。有编写文档的时间,倒不如用来对开发人员
进行培训,并获取他们的支持。在实践中,我们发现,人们往往不会
去真正阅读并理解大量的文档。文档过多也将使得工作失去重点。从
一些比较简单的、容易见效的、最好是能够结合现有的一些流行技术
的(程序员们都喜欢)。例如,使用用例技术来改进需求、使用 UML
来改进设计。这样做的好处还在于,这些技术往往都有较多的资料,
利用这些资料可以节省编写指南的时间。
开发人员应该要成为过程的主人,至少部分有能力和意愿的开发
人员应该成为。单凭管理人员或是外部顾问的力量是很难完成过程的
创建的。因此必须令开发人员主动投入到这项工作中来。我们认为软
件过程必须要能够结合具体的技术,因为这样,才能够吸引开发人员。
例如,版本控制工具的配置、集成测试环境的开发、单元测试技术、
设计模型等等。从技术出发,扩展到整个的软件过程,是一种渐进的,
但行之有效的方法。事实上,我们正是采用从定义面向对象软件框架
出发,来开始和完善过程定义的。这其实就是我们在 代码是最终目
的模式和 短期利益和长期利益的权衡模式中讨论的构架的形成过程。
不同的软件组织会有自己的路,但目标是一致的,就是通过一些有效
的活动,逐步引入软件过程,并令其在组织中开花结果。
如何把握过程控制的尺度
其实软件过程设计的思路和面向对象程序的设计思路是非常相似。
例如,在进行设计和程序的控制的之后,我们比较注重类的公有方法
部分和包的外观类部分,而对于类或包的内部实现并不很在意。因为
我们认为对于面向对象设计来说,公有方法或接口是最重要的,它们
设计的好坏直接关系到软件的好坏。因此,我们的思路是,把握关键
的检查点(就像我们在上一篇中提到的 KPI 的思路)。软件过程也是
类似。活动内部的信息交互并不是我们所关心的,只要活动能够产生
最终需要的信息就可以了。例如,在需求阶段,我们最关心最后的工
件---需求说明书。包括它的内容和外观。因为一方面它是后续活动的
基础,另一方面它需要交付给客户。为保证其顺利开发,我们设置了
需求审查会议。至于会议之前,开发人员喜欢用什么样的技术和方式
进行需求调研,并不是我们所关心的,而且,我们也乐意看到开发人
员尝试使用一些新的技术,这样才能够既保证了严谨,又保证了活跃。
因此,在开发过程中,把精力放在那些检查点上,只有力气用在刀刃
才才能达到最好的效果。在 知识接力模式中我们就谈到了检查点的
问题,此外,一些重要的活动,例如日创建和交付点,都是关键的检
查点。
如果你的过程比较严谨,开发人员并没有什么创新的机会或环境,
想办法制造一个。软件开发人员喜欢研究新的技术,这是他们的优点,
但是在项目中应用新技术是存在风险的(参见 短期利益和长期利益
的权衡模式)。鼓励并支持开发人员进行新技术的研究,并让其负责
这方面的事务。对团队,对个人都是有益的。
在 一致性的思考模式中,我们分析了工件和过程不一致时的对
策,并简单的谈到了推迟文档的实现的问题。这里我们继续这个话题。
没有多少程序员喜欢文档(这里的文档是广义的文档,包括模型、图
例、文字处理器文件、注释,它等同于我们在 知识接力模式中提到
的工件),而经理们则对文档又爱又恨,没有文档不行,这会造成知
识的流失;文档太多也不行,因为它需要大量的投入,并招致开发人
员的反感。因此,我们的建议是坚持以够用就好的思路对待文档,并
使用三种指导原则:
区分关键文档和普通文档。关键文档的信息收集工作应该不断
进行,虽然文档并不需要额外的修饰(就像 一致性的思考模式
中所说的),但是你要保证它把必要的信息都记录下来了。典
型的关键文档包括了需求模型、设计模型。普通文档的信息可
以从关键文档中取得,因此可以尽可能的延迟它的创建。例如
用户指南之类的文档。但是请注意,关键文档和普通文档只是
相对的概念,例如,你开发的如果是一个设计类的软件,那么
用户指南可能就成为关键文档,需要从一开始就考虑编写的工
作。如果有必要,你应当在软件过程中加入文档制作的活动,
以保证有充分的时间来处理它们。
在关键的检查点上保证文档的完整性和一致性。上文中我们提
到了检查点的概念。就像在需求复审这个检查点上,我们需要
保证需求模型完整的再现了用户或领域专家的思路,而在设计
复审这个检查点上,我们则需要保证设计模型和需求模型的一
致性,并确保开发人员和设计人员都同意当前的设计模型。只
在检查点上同步文档可以大大减少文档的负担,但文档需要进
行同步的检查点则要好好的考虑。例如,帮助文件需要同步的
检查点,界面原型需要同步的检查点。
使用工具来减轻文档的工作量。我们在 知识接力模式和 一致
性的思考模式中都提到了工具,这里我们再一次的强调它,但
我们不再这个问题上多费口舌了,大家可以参看两个模式中相
关部分的讨论。
总之,小心的处理文档,不要让文档成为开发人员怒气的焦点,
不要让编写文档变成一种应付了事的工作。这样的话,既花费了精力,
又得不到应有的效果。
最后一点,千万不要相信过程能够解决一切。"我们采用了最先
进的过程,我们一定能够成功的"这种话无异于痴人说梦。开发软件
的是人,而不是过程。好的过程对于软件的成功来说,只是一个必要
条件,而不是充分条件。永远依靠你的开发人员。当人的行为和过程
冲突或不一致的时候,想想过程的目的,再做最后的定论。
5、小结
在创建软件过程时,从现有的软件过程中选择一个适合自己的。
水无常形,软件过程也是一样,确保它随着时势而变。
注意引入软件过程的开始阶段,让开发人员参与到软件过程中
来。
重点关注检查点。
保持文档活动的敏捷性。
过程不是仙丹,人才是。
六、短期利益和长期利益的权衡
软件过程的改进是一个长期的过程,属于长期的利益。如果长期
利益和短期利益相冲突的时候我们应该如何处理。我们有什么办法来
令短期利益和长期利益结合起来呢?
1、意图
权衡短期利益和长期利益。
2、示例
金商软件是一家专门针对小型企业销售软件产品和定制开发的公
司。他们销售的软件来自于国内的一家知名软件厂商。而公司内部的
软件人员主要从事定制开发,一方面是满足用户的一些特殊需要,另
一方面是为了发展自己的软件开发力量,以图日后开发出自己的产品。
这种策略刚实施了半年的时间,目前公司的开发人员只有 5 个人。由
于公司的销售能力很强,因此公司总是能够得到大量的订单。由于公
司目前已经拥有开发力量,因此得到的订单也不像从前,以产品为主,
定制为辅。而是一些完整的开发项目。从 10 月份开始,公司已经签
了 4 个项目,按照公司的习惯,一般都承诺在 3 个月内完成项目。可
是根据软件部分的估算,目前的任务,大概需要 60 个人月的时间。
到了 11 月,开发部的所有人员已经连续加班 1 个月了。其中 2 个项
目由于增加需求,同意把项目的开发周期延长一个月,但是和 60 个
人月的工作量比起来,这点时间似乎是杯水车薪。在时间的强大压力
之下,开发人员不得不牺牲软件质量,而软件的最后完工看起来是那
么的遥不可及。
3、分析
自从加入到面向对象开发地阵营以来,我们深为这门开发艺术所
感动。编码工作在面向对象思想的指导下显得那么具有美感。以往过
程式编码失控之后的那种无力感再也找不到了。面向对象带给我们的
是极大限度的重用性,当然,我们需要付出前期投入的成本。从学习
面向对象以来,我们学会了使用一种抽象的方式看待世界,思考问题。
有些时候,我们同一些仍然保持传统编程习惯的软件公司交流时,我
们发现似乎面向对象并没有体现出太大的优势:
"面向对象技术可以极大的重用现有的构架,大大提高开发速度。"
"我们现在通过增加人手和加班的方式,也能够很快的完成一个项
目。"
"面向对象技术可以减少软件的维护成本。"
"一般我们会指定一些开发新手来维护公司以往的项目,这方面的
成本并不高。"
"面向对象能够不断的积累项目经验,为后续的项目开发提供保证。
"
"通过雇佣有经验的开发人员,我们可以直接获得开发经验,而不
用自己积累"
"面向对象是未来软件开发的主流。"
"保证项目及时完成是管理层最关心的,等到市场上的面向对象程
序员足够多之后我们再采用面向对象吧。"
"此外,现在采用面向对象,人员需要全新的培训,我们没有多余
的人手;由于没有经验,直接把面向对象用于项目实施存在风险,而
我们的项目时间都太少了"
这一段对话点出了面向对象技术的困惑,但也反映了软件开发中
短期利益和长期利益的冲突。
4、问题
如何在软件开发的短期利益和长期利益中寻求平衡点?
5、方法
面向对象的迷思
我们的疑惑是从面向对象开始的 。归结其原因,是我们并没有真
正的认识面向对象。
"面向对象符合现实世界的特性,因此会更加简单。"
"我们决定从这个项目开始采用面向对象技术,并安排了为期 2 周
的学习时间。"
"由于采用了先进的面向对象技术,我们把开发周期缩短 1/3。"
如果你对面向对象有上述的理解的话,说明你对面向对象技术的
理解存在误区。首先,面向对象和面向过程的不同在于思维方式的根
本不同,因此,转向面向对象技术决不是一个一蹴而就的过程,而是
需要不断的学习,不断的磨练。如果需要为这个学习过程制定一个时
间的话,我想也应该是在 8~14 个月之间。其次,在刚开始采用面向
对象技术时,并不能够节省项目的开发时间,相反,因为学习和尝试
面向对象技术的需要,项目的所需时间会大幅度延长。面向对象技术
的威力在经过一段时间的积累之后会慢慢的显露出来,你会发现一个
新的软件只需要对现有的类进行重用,编写少量的代码,甚至使用代
码生成器就能够完成。这使得软件的开发成本大幅度的降低。这个时
候,软件开发将会进入良性循环的周期。
为什么面向对象技术会有如此大的威力呢?原因在于面向对象
的抽象思维。
了解了面向对象的知识之后,我们发现其实面向对象的主要威力
是它使用一种特定的方法,将一些不断重复的事情简化了。问题在于,
要让软件组织学会使用这种方式是需要代价的。那么,你是否愿意付
出这种代价?今天付出 1 块钱,明天能够收回 10 块钱的事情每个人
都会做。但是让你每天投入 10000 块钱,坚持 2 年,这样你会在未来
获得 10 倍的回报。这种事情就未必会有人做了。研究面向对象技术,
发展软件组织的技术框架需要很大的前期投入,而效益却是慢慢显现
的。这就造成了短期利益和长期利益的矛盾。其实,除了面向对象技
术之外,软件组织中还存在很多同种性质的矛盾:
所有人都知道项目管理的必要性,甚至言必谈项目管理,但是
真正按照项目关联方式执行的又有多少人呢?
软件质量是软件组织最看重的,但是由于人员和时间的压力而
牺牲质量的案例多如牛毛。
计划制定和执行是软件过程中最核心的部分,可是计划赶不上
变化也是目前最流行的口头禅。
由于我们主要讨论的仍是经验,关于项目管理的原理、案例、数
据的资料有很多书籍都有介绍,因此我们就不用再次的重复它们了。
而我们的出发点,仍然是围绕着前述的核心矛盾,介绍一些实践。这
些实践并不需要很大的成本,但是确实能够起到很好的效果,当然,
它们最能够发挥作用的前提条件是--"坚持"。从下面的介绍来看,其
目的都是为了补充或完善框架的问题。在之前的模式中,我们多次提
到这个词。这里我将给出其定义:
框架是软件组织对技术、实践、方法、过程、经验的有序积累。
用时髦的话来说,就是知识管理。框架不是一开始就存在的。它
需要积累,它的内容很广泛,不仅仅包括技术,还包括项目经验、软
件过程、管理思想、组织设计等等内容。和开发软件相关的内容,它
都包括。框架能够避免软件组织不断的发明轮子,能够将原先存在于
人员脑中的隐性知识转换为显性知识。但是如果你没有一个清晰的建
立框架的思想,没有一个明确的框架发展目标。框架是不会自动出现
的。
坚持面向对象技术的学习和使用。我们已经花了一部分的篇幅讨
论面向对象的优点。那么我们如何评估它呢?首先,如果软件组织没
有面向对象的经验,最好的方式是求助外界,无论是培训,还是聘请
面向对象开发人员都是有用的。光凭自身的积累是比较慢的。其次,
慎重的使用面向对象技术。作为一种新的技术,总是存在较大的风险。
因此,尝试的在一些较小规模的项目中使用它,切忌急功近利。对于
完成的面向对象的设计,应该将其纳入到框架中。
纳入到框架中的设计和代码需要严格对待。因为它将会成为权威
性的资料。设计需要经过复审,代码需要通过测试。此外,还需要配
套必要的文档。必须要讲清楚为什么要这样设计,设计的思路,达到
的目的,可能适用的环境。这些都会对读者产生帮助。现实中,我们
发现模式语言是一种很好的编写文档的格式。因为它的名称、意图、
上下文、问题等部分给出了解决方案的前导叙述,能够让读者迅速浏
览,并判断该模式的价值。而解决方案、相关模式、已知应用等部分
在描述了解决方案的同时还扩展了读者的思路。而模式语言的可扩展
性也意味着你可以根据自己的需要加入不同的元素。
在框架中建立项目经验库是很好的做法。但并不是所有的软件组
织都能够做到这一点的。因此我们采用一种折衷的方法。对上一次项
目经验进行复审。在每一次的项目开始之前,我们都需要问问自己,
上一次项目有什么成功和失败的地方,这次的项目如何利用成功经验,
吸取失败的教训。可以采用会议的形式。这会起到很好的效果,但不
要让这种会议流于形式。
长期利益和短期利益的结合
软件工程并不意味着轰轰烈烈的公司运动,至少我是这么认为的。
也许我属于温和派,比较倾向于逐步的改进软件过程。很多时候,优
良的软件过程往往来源于平时的日积月累,一点点微小的改进。说明
这一点最有效的证据就是软件度量。我们知道,软件度量是一个很重
要的概念,在实际工作中也非常的实用,例如,我们可以统计出软件
组织中单个人月的价格,可以统计出完成某个人完成某个模块的时间
长度。可是软件度量需要一个长期的数据收集的过程,但这个工作一
旦完成,就能够作为进度控制的基础。软件度量并不是本文讨论的重
点,但是应该认识到,软件度量的工作,就属于典型的长期利益的工
作,而平时的工作量其实不大,关键在于要有这方面的投入。
从某个方面上说,软件度量也可以纳入到可重用框架中。在可重
用框架的范畴中,像这种长期利益和短期利益并不矛盾的例子还可以
找出很多。例如单元测试。现在的软件组织已经日益的强调测试了。
但是测试工作往往存在着很多误区,直接导致的后果就是成本上去了,
但是并没有获得预期的高质量。由于人员的增多,流程的复杂化,还
会产生不少诸如沟通之类的额外的问题。为什么呢?其实测试产生的
很多问题是因为软件过程的上游没有做好的缘故。例如需求的缺陷或
是设计的缺陷。越是上游的软件活动,在出问题的时候,对测试工作
的杀伤力越大,这一点和变更是相同的。因此,测试人员的主要工作
应该是要解决这类的问题,让测试人员参与到需求分析或是设计工作
上来,能够有效的改进软件的质量。但是目前测试人员大部分的时间
往往是在处理一些代码级别的缺陷。这实际上是比较浪费测试人员的
宝贵精力的。因此,XP 中倡导的单元测试能够让编码人员自行处理
代码级别错误,从而让测试人员把精力放在更重要的部分上。像这样
的实践,见效快,并不需要很大的投资。唯一需要投入的就是对目前
的软件流程进行分析和改进。
长期利益和短期利益的另一个例子是一致性。在软件组织发展的
初期,一致性问题往往并不明显。更重要的目标是完成软件的功能,
至于实现的过程并不被关心的。但是随着软件组织的发展,积累的增
多,渐渐就会出现重复的代码、不规范的设计、混乱的软件。当这些
问题发展到非常严重的地步,已经严重影响到软件组织的发展的时候,
你会惊讶的发现,解决这些问题的代价是极为高昂的。其实,这些问
题如果能够早些加以重视,原本是不会发展成为一个可怕的泥潭的。
例如,针对出现软件设计混乱的情况,就应该制定标准、规范的设计
框架;针对代码重读、不标准的问题,就应该通过代码模版、复审等
活动来加以规范。软件工程的真正意义往往就体现在这些看似不起眼
的活动上。不注重短期的投入,往往会损害长期的利益。其实,上述
的问题还可以做的更好一些。在 MDA 的概念中,提到了模式和企业
应用的关系。MDA 认为,利用模式来作为描述业务对象的基础,并
把模式根据抽象程序进行分层,可以极大程序的实现重用,并可以保
持业务对象模型中的一致性。
软件组织对软件过程的改进很难做到彻底的,革命性的。更多的
时候,我们是在"补短板",就像是木桶理论所说的,发现哪一块的木
板最短,就改进哪一块。但是要正确的识别出最短的木板也不是一件
容易的事情。因为软件过程中的各个活动具有高度的关联性。确实需
要花时间来对过程进行分析。
6、小结
处理好短期利益和长期利益的关系。
根据软件过程的特点决定选取实用的实践。
我们从面向对象技术开始我们的讨论。其目的有二:一是介绍面
向对象的经验;二是引出我们的主题---如何缓解短期利益和长期利益
的矛盾。(注意我们使用缓解一词,而不是解决。)