本文内容包括: 来自 Rational Edge:作为IBM Rational的六个最佳软件开发实践的主要更新,本文阐述了一组新的原则,可用来刻画构建,部署和演化软件密集系统的成熟方法。 从1983年——现在的IBM Rational,那时叫做Rational软件——组织成立起之时,我们关于各种软件开发过程和技术的知识一直在增长——通过与客户和合作伙伴的广泛合作。多年来,他们中的很多人加入了我们的组织,并在我们学习哪些方法是有效的,哪些是无效的,以及为什么软件开发始终是一个充满挑战性的工作的过程中,不断塑造着我们对软件开发实践的理解。 正如我们的客户,合作伙伴和雇员多次听我们说到的那样,软件开发是一项团队工作。理想化地,软件开发活动涉及了良好协调的团队在各种涵盖了整个软件生命周期的规则约束下的工作。但是它不是科学,也不是精确的工程——至少从基于事实的可计量原则的观点看不是。那些假设你可以计划并建立分离的软件部分然后把它们组装起来,就像你造桥或宇宙飞船那样的软件开发活动总是不能按时完成,不能在预算范围内完成,也不能让客户满意。 因此,在缺乏严密论据的情况下,Rational组织依赖于我们称之为最佳实践的软件开发技术,这些技术的价值在我们为客户进行的服务中反复得到了证实。它们描述了一个迭代的,递增的,引导开发团队实现结果的过程,而不是为一个软件项目指示一个计划-建立-组装的活动序列。 十多年以来,我们的六个经检验正确的最佳实践一直是我们的工具和过程改进的基础。今天,我们有更多公司把软件开发作为核心业务能力来进行研究,于是我们也就看到了这些最佳实践在更广泛的业务驱动开发的环境下的不断成熟。我们认为现在需要对不断演化的系统的更长生命周期(在这个周期中主要演化的元素是软件)重新阐释我们的最佳实践了。 本文阐释了一组原则,我们认为这些原则描述了构建,部署和改进软件密集型系统的工业最佳实践的特征:
我们将按顺序解释上述这些原则,描述最好地体现了每条原则的行为模式,以及最常见的对软件开发项目造成破坏的“反面典型”。
更多的过程,比如使用更多工件,产生更详细的文档,开发和维护更多需要进行同步的模型,进行更多形式化评论,并不一定有好处。实际上,你需要根据项目需要正确裁减过程的大小。随着项目规模的不断增长,分布范围变得更广,使用更复杂的技术,拥有更多数量的涉众,需要遵循更严格的标准,过程也就需要更多地遵守原则。但是,对于小型的,团队在同一地点工作的,使用广为人知的技术的项目来说,过程应该是较为轻量级的。这些依赖关系如图1所示。 第二,项目应当使过程适应整个生命周期的各个阶段。在项目的开始,你有很多不确定因素,你希望有更多创造性来开发一种明确业务需求的应用程序。更多的过程往往导致较少的创造性,而不是更多,因此你应当在项目初始,不确定性是最常见因素之时使用较少的过程。另一方面,在项目后期,你往往想要引入更多控制,比如变更控制板,来消除不想要的创造性和相关风险,以免在晚期引入缺陷。这就意味着在项目晚期使用较多过程。 第三,一个组织应当努力地 不断改进过程。在每次迭代和每个项目最后作一个评估来获得学到的经验,并把这些知识用于改进过程。鼓励所有团队成员不断寻找改进的机会。 第四,在项目的不确定性和项目计划以及相关估计中取得平衡。这意味着在项目的早期,不确定性很大的时候,计划和相关的估计应集中于全景的计划和估计,而不是着眼于在什么都没有的情况下提供精确到五位的数据。早期开发活动的目标应是找出不确定性来逐渐在计划中提高精确性。 图1:驱动过程原则的数量因素很多因素,包括项目规模,团队分布,技术复杂度,涉众数量,灵活性需求,以及你在项目生命周期中所处的位置,指出了你需要何种规范程度的过程。 这一原则的反模式是永远认为更多过程和更详细的前景计划是更好的。强制进行早期估计,并依赖于这些估计。
这一原则阐述了平衡业务和涉众需要的重要性,两者往往是冲突的。作为例子,多数涉众希望应用程序可以完全实现他们想要的功能,同时最小化应用程序的开发成本和时间表。但是这些优先权经常是冲突的。例如,如果你使用一个包装好的应用程序,你可能能够更快,并以更低的价格发布方案,但是你不得不牺牲很多需求。另一方面,如果一个公司决定从底层构建一个应用程序,它可能可以实现所有需求,但是预算和项目完成需要的时间将同时超过它们可行的极限。 我们要做的不是叫我们的程序设计团队攻克需求清单中每一个元素;我们要做的第一件事是理解并排列业务和涉众需要的优先次序。这意味着掌握业务过程并把它们同项目和软件功能联系起来,这使得我们能够有效地排列出正确的项目和正确的需求,并随着我们对应用程序和涉众需要理解的深入修改我们的优先次序。优先级的排列还意味着我们需要在项目中加入客户或客户代表,来保证我们理解了他们的需要。 第二,我们需要围绕涉众需要开展开发活动。比如,通过利用用例开发和以用户为中心的设计,我们可以接受这样一个事实:随着业务的变化,以及我们对哪些功能对业务和终端用户更为重要的更好理解,在项目的持续过程中涉众的需要会发生演化。我们的开发过程需要适应这些变化。 第三,我们需要理解哪些资产是可用的,然后平衡资产复用和涉众需要。资产的例子包括继承应用程序,服务,可复用组件,和模式。在很多情况下资产的复用导致更低的项目成本;而对经过验证的资产,对它们的复用通常意味着新应用程序的更高质量。缺点是,在很多情况下,你需要牺牲资产复用而精确地实现终端用户的需要。对一个具体功能,复用一个组件可以降低开发成本达80%,但是它可能只能实现75%的需求。因此,有效的复用需要你不断地平衡资产复用和发展中的涉众需要。 图2:平衡需求处理组件的使用。使用一个组件可以从根本上降低成本和发布一组特定功能的时间。在很多情况下它可能还需要你牺牲一些功能或技术需求,比如平台支持,性能,或覆盖区(应用程序的大小)。 遵循这一原则的反模式是在项目开始详细记录精确的需求,强制涉众接受需求,然后对需求的变更进行协商,而需求的每一点变更都将增加项目的成本或持续时间。由于你一开始就锁定了需求,你降低了使用已有资产的能力,于是迫使你进行定制化的开发。另一个反模式是构建一个只能满足最强势的涉众的需求的系统。
软件是由有才能,有动力,并紧密合作的人制造的。很多复杂的系统需要一定数量的有不同技能的涉众的活动,而最大的项目常常跨越地理和时间的界限,进一步增加了开发过程的复杂度。这就是人的问题和协作——称之为软件开发的“软”元素——成为了灵活开发的主要焦点的原因。1 这一原则指出了很多问题,包括:你如何激励人们,使他们的表现最好?在一个在同一地点的软件团队内,在一个分布式团队内,在共同参与一个业务活动,软件开发,和IT运作的不同团队之间,你如何与人合作? 有效合作的第一步是激励团队中个人的最好表现。自我管理团队的概念2 在灵活性目标中正在受到越来越多的关注;它是基于使一个团队专注于他们要发布的产品,然后为他们提供决定所有直接影响结果的问题的权力的。当人们感到他们真正要对最终产品负责的时候,他们被激励去很好地完成工作。正如灵活性宣言陈述的:“在被激励的个体周围建立项目。给他们需要的环境和支持,并相信他们将会完成任务。” 第二步是鼓励跨职能的合作。很多年前我们就指出,“软件开发是一项团队工作。”一个迭代的方法增加了作为一个团队紧密工作的需要。我们经常需要打破建立于分析师,开发者和测试者之间的阻隔,并拓宽成员的角色职责以保证迅速变化的环境下的有效合作。每一个成员需要理解项目的任务和远景。 随着我们的团队的增长,我们需要提供有效的合作环境。这些环境方便了度量收集和状态报告,并使围绕配置管理的构建管理和日志自动化。这一有效性使得更少的会议成为可能,这样团队成员可以花更多时间在生产和创造性活动上。这些环境还应通过简化交流,沟通不同团队成员在时间和地域上的阻隔来实现更有效的合作。这种环境的例子包括了从共享项目房间到网络或基于网络的方案,比如Wikis或集成开发环境和配置及变更管理环境。 在这个原则下我们的最终目标是集成化的跨业务,软件和运作团队间的合作。随着软件在我们如何运作我们的业务中变得越来越重要,我们需要与1)决定如何运作我们现有的和将来的业务的团队,2)开发支持软件系统的团队,以及3)运作我们的IT业务的团队进行紧密的合作。 图3:跨业务、开发和运作团队协作。随着软件在我们如何运作我们的业务中变得越来越重要,我们需要与负责如何运行业务,如何开发应用程序,以及如何运行应用程序的周围团队更紧密地合作。在多数公司中,这三个小组的交流很糟糕。 这一原则的反模式是培养英雄式的开发者,他们愿意超长时间工作,包括周末。一个相关的反模式是培养高度专业的人,并为他们的工作配备有强大工具,他们与其它团队成员的合作很有限,而且不同工具间的集成也很有限。这里的假设是如果每个人都做好他自己的工作,最终结果就会是好的。
这一原则下有若干隐含规则。首先,你想要交付增量价值来获得早期的和连续的反馈。这是通过把我们的项目划分为一组迭代过程实来现的。在每次迭代中,你完成一些需求,设计,实现,和对你的应用程序的测试,因此产生了一个距最终方案更进一步的发布。这使得你能够向终端用户和其它涉众演示应用程序,或让他们直接使用应用程序,使他们能够对你的工作做出快速的反馈。你进行的方向正确吗?涉众对你到目前为止的工作满意吗?你需要改变已经实现的特性吗?还有哪些特性需要被实现以增加业务价值?通过对这些问题做出令人满意的答复,你将会因发布实现涉众需要的系统在涉众中建立信任。同时你也不大会把工作做过头,加入对终端用户没有用处的功能3。 第二条规则是利用演示和反馈来调整你的计划。你需要做的不是依赖于评估规范,比如需求规范,设计模型,或者计划,你需要评估的是已经开发出来的代码的实际工作情况。这意味着你集中于测试结果并向不同涉众演示工作代码,使他们可以评估你的进展。这为你提供了一种良好理解,包括你在何处,在你的开发环境下团队可以以什么样的速度取得进展,以及为了成功完成项目你是否需要对过程进行校正。你使用这些信息来更新项目计划并为下一次迭代开发更详细的计划。 隐含的第三条规则是包含并管理变更。现在的应用程序太过复杂,以致你无法一次很好地排列需求,设计,实现,和测试。取而代之地是,最有效的应用程序开发方法包含了不可避免的变更。通过早期和连续的反馈,我们了解了如何改进应用程序,而迭代的方法为我们提供了逐渐实现这些变更的机会。所有这些变更需要通过合适的过程和工具来管理,这样我们就可以有效地管理变更而不影响我们的创造性。 这一原则隐含的第四条规则是在生命周期尽早发现关键风险4,如图1所示。你必须尽可能早地指出主要技术,业务和编程风险,而不是把风险的解决推迟到项目的最后。这是通过不断评估你面对的风险,并在下一次迭代中解决剩余风险中最重要的一个来实现的。在成功的项目中,早期的迭代包含涉众确定一个远景买进和高级需求,包括架构设计,实现,和用以减轻技术风险的测试。有一些信息需要被用来决定使用哪些可复用的主要资产或非销售(COTS)软件,保留这些信息也是很重要的。 图4:瀑布和迭代开发项目的风险消减一览图。迭代开发的一个主要目标是在早期消减风险。这是通过分析,排列优先级,和在每次迭代过程中解决最大风险来实现的。 一个典型的反模式(即,过去的导致项目失败的软件开发实践)是在整个生命周期开始前制定详细的计划,然后通过计划跟踪变化。另一个反模式是依赖于评审规格来在项目的前三分之二处评价项目状态,而不是评估测试结果和工作软件的演示情况。
在软件开发中我们面对的一个主要问题是复杂度。我们知道降低复杂度对生产力有很大影响。5在更高的抽象层次工作降低了复杂度并使交流变得容易。 一种有效降低复杂度的方法是复用已有资产,比如可复用的组件,继承系统,已有业务过程,模式,或者公开源码软件。两个关于复用的很好的例子在上一个十年对软件工业产生了巨大影响,它们是对中间件的复用,比如数据库,Web服务器和入口,以及后来的对公开源码软件的复用,它们提供了或大或小的可利用的组件。今后,Web服务可能会对复用产生主要影响,因为它们提供了在完全不同的平台上,以及客户和服务的提供者之间只有松散耦合的情况下复用主要的大块功能的简单方式,如图6所示。这意味着你可以更容易地采用不同的服务组合来实现业务需要。公开标准,比如RAS,UDDI,SOAP,WSDL,XML和UML,也方便了复用。 图5:通过面向服务的架构复用已有资产。 复用的问题之一是在开发时两个组件需要知道对方的存在。面向服务的架构通过提供所谓的“松散耦合”减轻了这个问题,在图中由黑色双箭头指示。某服务的客户可以动态地找到一个服务的提供者。因此你可以把已有的组件或继承系统包装起来,允许其它组件或应用程序通过一个基于标准的接口动态地访问它们的功能,并且这种访问是独立于平台和实现技术的。 另一种降低复杂度和改善交流的方法是利用高级工具,框架和语言。标准语言,比如统一建模语言(UML),和快速应用语言比如EGL6提供了表达高层构建,比如业务过程和服务组件,方便了其周围的高级构件的合作而同时隐藏了不必要的细节。设计和构建工具可以通过提供自动化设计,构建,和测试任务的向导来自动化从高级构件到工作代码的转移,而向导的自动化功能是通过产生代码和允许代码片段的使用,以及把集成和测试通过集成化开发,构建,和测试环境转变为无缝开发任务实现的。另一个例子是项目和证券管理工具,它们使你能够把多个项目的金融和其它方面作为一个实体来管理,而不是作为一组分离的实体来管理。 管理复杂度的第三种方法是集中于架构,无论你正试图定义一个业务还是开发一个系统或应用程序。在软件开发中,我们的目标是设计一个架构,实现它,并在项目的早期就进行测试。这意味着在项目的早期我们要定义高级构建模块和最重要的组件,它们的功能和接口。我们定义和实现系统机制,也就是对常见问题的现成解答,比如如何处理一致性和碎片收集。通过尽早正确建立架构,我们为系统定义了一个骨架,使得当我们向项目中加入更多的人,组件,功能和代码的时候管理复杂度比较容易。我们还认识到我们可以利用哪些可复用资产,以及系统的哪些方面需要定制。 这一原则的反模式是直接从模糊的高级需求发展出定制的代码构思。由于基本没有进行抽象,在代码级而不是一个更概念化的级别上进行了很多讨论,这就失去了很多复用等的机会。掌握的非形式化的需求和其它信息需要很多决定和规范来不断重新访问,而对架构的有限的强调造成了在项目后期的主要返工。 持续关注质量
提高质量不是简单的“满足需求”,或是生产一种满足用户需要和期望的产品。质量还包括了确定展示产品的成果的量度和标准,以及一个保证团队创造的产品实现了期望的质量水平的过程的实现——这一过程可以被重复和管理。 保证高质量不只需要测试团队的参与;它需要整个团队关注质量。这涉及了所有团队成员以及生命周期的所有部分。分析师对确定需求的可测试性负责,而且我们还要明确对测试的需求。开发人员需要在设计过程中考虑到测试,并必须对测试他们的代码负责。管理人员需要保证正确的测试计划在正确地实施,正确的资源在适当地用于建立测试件并进行需要的测试。测试员是质量专家。他们指导团队的其余成员理解软件质量问题,他们对功能,系统和性能级的测试等等负责。当我们经历一个质量问题时,每一个团队成员都应积极参与阐述这个问题。 迭代开发的主要优势之一是它使一种尽早地并且不断地测试方法成为可能,如图2所示。由于最重要的功能在项目的早期就被实现了,在你达到末期时,本质的软件可能已经成型并运行几个月了,而且可能已经经过了几个月的测试。多数采用迭代开发方法的项目声称改进过程带来的主要结果之一是质量的提高,这也就是意料之中的了。 在我们逐步建立我们的应用程序的同时,我们还应该逐步建立测试自动化来及早发现缺陷,同时使前期投资最小化。在你设计你的系统时,考虑到它将如何被测试。做出正确的设计决定可以在很大程度上提高你的自动化测试能力。你还可以直接从设计模型中产生测试代码。这节省了时间,为早期测试提供了动力,并通过最小化测试软件中的缺陷提高了测试的质量。自动化测试已经成为灵活性关注的焦点,而灵活性的目标是使所有代码的测试自动化,并且测试是在代码编写前编写的(所谓的测试先行的设计)。 图6:测试在早期被启动并在每一次迭代中被扩展。迭代开发使早期测试成为可能。软件在每次迭代中被建立起来,并且在建立过程中就经过了测试。回退测试保证了当新的迭代添加了功能时没有引入新的缺陷。 这一原则的反模式涉及对所有中间工件进行深入详细的回顾分析,这对生产效率是不利的,因为它延迟了应用测试,也就延迟了主要问题的识别。另一个反模式是在进行整体测试前完成所有单元测试,援引同样是延迟了主要问题的识别。 正如我们开始时注意到的,这些原则是从十余年前它们的原型演化而来的,那时软件开发者的工作环境基本上是更为有限的。我们关于软件开发的知识,以及项目成功的整体条件,都逐渐成熟并不断扩展。今天的业务驱动的软件开发组织需要眼界更为广阔的指导,这包括了地理分布开发,IT管理和规则服从需要,面向服务架构,等等。 正如软件开发不是严密的科学,我们相信这些原则不应当被当作绝对的条款,或永恒的真理,而是作为一种改进软件项目结果的指导。这些原则还将继续演化——不是以很快的速度,但是逐渐的,随着我们掌握更多关于哪些方法有效,哪些无效等等的经验。不变的一点是Rational帮助客户(他们的业务依赖于开发和部署软件)取得成功的长期不懈的努力。 |