2.2 软件过程模型
软件工程(第4版?修订版)
软件工程文献描述了很多软件过程模型。有些模型是规定性的(prescription),说明软件开发应该进行的方式;而另一些是描述性的(description),说明软件开发实际进行的方式。从理论上讲,两种类型的模型应该是相似或相同的,但事实并非如此。建立过程模型并讨论它的子过程有助于开发团队理解开发过程的理想情况与实际情况之间的差距。
对过程进行建模的原因还有很多。
当一个小组记录下开发过程的描述时,就会形成对软件开发中的活动、资源和约束的共同理解。
建立过程模型有助于开发团队发现过程及其组成部分中存在的不一致、冗余和遗漏的地方。当注意并改正了这些问题以后,过程会变得更加有效并且集中在构建最终产品上。
模型应该反映开发的目标,例如构建高质量的软件、在开发的早期发现故障以及满足必需的项目预算和开发进度的约束。由于建立了模型,开发团队可以根据目标评估候选活动是否合适。例如,开发团队可能引入需求评审,这样可以在设计开始之前发现和修复需求中的问题。
应当根据具体情况对每一个过程进行裁剪。建立过程模型有助于开发团队理解应该在哪里对过程进行裁剪。
每一个软件开发过程模型都将系统需求作为输入,将要交付的产品作为输出。多年来,人们提出了很多模型。这里探讨几种最流行的模型,以理解它们之间的共性和区别。
2.2.1 瀑布模型
研究人员提出的第一个模型是瀑布模型(waterfall model),如图2-1所示,它将开发阶段描述为从一个阶段瀑布般地转换到另外一个阶段(Royce 1970)。如该图所提示的,一个开发阶段必须在另一个开发阶段开始之前完成。因此,当从客户引发的所有需求都已经过完整性和一致性分析,并形成需求文档之后,开发团队才能够开始进行系统设计活动。瀑布模型从一种非常高层的角度描述了开发过程中进行的活动,并且提出了要求开发人员经过的事件序列。
瀑布模型一直被用来规范软件开发活动。例如,美国国防部标准2167-A规定,瀑布模型是多年来国防部合同中软件开发交付的依据。每一个过程活动都有与其相关联的里程碑和可交付产品,以便于项目经理能够用模型判断在某一时刻项目离最后完成还有多远。例如,在瀑布模型中,“单元测试和集成测试”阶段结束的里程碑是“编写完经过测试和集成的代码模块”,其中间可交付产品是测试过的代码的副本。接着,代码被移交给系统测试人员,这样它可以与其他系统构件(硬件或软件)合并,并作为一个整体进行测试。
在帮助开发人员布置他们需要做的工作时,瀑布模型是非常有用的。它的简单性使得开发人员很容易向不熟悉软件开发的客户做出解释。它明确地说明,为了开始下一阶段的开发,哪些中间产品是必需的。很多其他更复杂的模型实际上是在瀑布模型的基础上的润色,如加入反馈循环以及额外的活动。
通过引入加强理解的活动和子过程,软件开发过程有助于控制活动之间的往返。原型化就是这样的一个子过程。原型(prototype)是一个部分开发的产品,它使客户和开发人员能够对计划开发的系统的相关方面进行检查,以决定它对最终产品是否合适或恰当。例如,开发人员可以构建一个系统来实现一小部分关键需求,以确保需求是一致、可行和符合实际的。否则,在需求阶段就要进行修正,而不是在测试阶段(测试阶段代价会更高)进行修正。同样,设计的某些部分也可以进行原型化,如图2-3所示。设计的原型化有助于开发人员评价可选的设计策略以及决定对于特定的项目,哪一种策略是最好的。正如我们将在第5章中看到的,设计人员可能用几种完全不同的设计来处理需求,看一看哪一种具有最好的特性。例如,可以在一个原型中把 络设计为环形的,而另一个设计为星形的。然后评价其性能特性,看一看哪一种结构能更好地满足性能目标或约束。
该模型中连接V形符 左边和右边的连线意味着,如果在验证和确认期间发现了问题,那么在再次执行右边的测试步骤之前,重新执行左边的步骤以修正和改进需求、设计和编码。换言之,V模型使得隐藏在瀑布模型中的迭代和重做活动更加明确。瀑布模型关注的通常是文档和制品,而V模型关注的则是活动和正确性。
2.2.3 原型化模型
我们已经看到如何使用原型化活动修正瀑布模型以改进对系统的理解。但是原型化不仅仅是附属于瀑布模型的,如图2-5所示,它本身也是一种有效的过程模型的基础。由于原型化模型允许开发人员快速构造整个系统或系统的一部分以理解或澄清问题,因此,它与工程化原型具有同样的目的,其中需要对需求或设计进行反复调查,以确保开发人员、用户和客户对需要什么和提交什么有一个共同的理解。依据原型化的目标,可以取消原型化需求、设计或系统中的一个或多个循环。但是,总体目标保持不变,即减少开发中的风险和不确定性。
例如,系统开发可能以客户和用户提出的一组需求为起点,然后,让相关各方一起探讨各种方案,查看可能的屏幕显示、表格、 表以及用户和客户直接使用的其他系统输出。当用户和客户对需要什么做出决定时,对需求进行修正。一旦对需求应该是什么达成了共识,开发人员就可以进行设计了。再次通过同样的过程,开发人员与客户和用户协商来探讨不同的设计。
2.2.5 可转换模型
Balzer的可转换模型(transformational model)通过去除某些主要开发步骤来设法减少出错的机会。利用自动化手段的支持,转换过程使用一系列转换把需求规格说明变为一个可交付使用的系统(Balzer 1981a)。
转换的样例有:
改变数据表示;
选择算法;
优化;
编译。
由于从规格说明到可交付系统可以采取很多途径,它们所表示的变换序列和决策都保存为形式化的开发记录。
转换方法具有很好的前景。然而,如图2-7所示,应用转换方法的主要障碍在于需要一个精确表述的形式化的规格说明,这样才可以基于它进行操作。随着形式化规格说明方法的普及,转换模型将会被更广泛地接受。
开发人员可以用多种方法决定如何将开发组织为发布。增量开发(incremental development)和迭代开发(iterative development)是两种最常用的方法。在增量开发中,需求文档中指定的系统按功能划分为子系统。定义发布时首先定义一个小的功能子系统,然后在每一个新的发布中增加新功能。图2-9的上半部分显示了增量开发是如何在每一个新的发布中逐步增加功能直到构造全部功能的。
螺旋模型的每一次迭代都根据需求和约束进行风险分析,以权衡不同的选择,并且在确定某一特定选择之前,通过原型化验证可行性或期望度。当风险确认之后,项目经理必须决定如何消除风险或使风险降到最低。例如,设计人员不能确定用户是否更喜欢某一种界面(相比较于另一种界面)。用户有可能会选择阻碍高效率使用新系统的界面,要把这种选择的风险最小化。设计人员可以原型化每一个界面,并通过运行来检验用户更喜欢哪一种界面。甚至可以在设计中选择包含两种不同的界面,这样用户能够在登录的时候选择其中一个。像预算和进度这样的约束有助于确定要选择哪一种风险管理策略。第3章将更详细地讨论风险管理。
2.2.8 敏捷方法
从20世纪70年代到90年代提出并使用的许多软件开发方法都试图在软件构思、文档化、开发和测试的过程中强加某种形式的严格性。在20世纪90年代后期,一些抵制这种严格性的开发人员系统地阐述了他们自己的原则,试图强调灵活性在快速有效的软件生产中所发挥的作用。他们将他们的思想整理为“敏捷宣言”,概括为以不同的方式思考软件开发的4条原则(Agile Alliance 2001)。
相对于过程和工具,他们更强调个人和交互的价值。这种观点包括给开发人员提供他们所需的资源,并相信他们能够做好自己的工作。开发团队将他们组织起来,让他们进行面对面交互式的沟通而不是通过文档进行沟通。
他们更喜欢在生产运行的软件上花费时间,而不是将时间花费在编写各种文档上。也就是说,对成功的主要测量指标是软件正确工作的程度。
他们将精力集中在与客户的合作上,而不是合同谈判上,从而,客户成为软件开发过程的一个关键方面。
他们专注于对变化的反应,而不是创建一个计划而后遵循这个计划,因为他们相信不可能在开发的初始就能预测到所有的需求。
敏捷开发的总体目标是通过“尽可能早地、持续地交付有价值的软件”使客户满意(Agile Alliance 2001)。很多客户都有一些随着时间变化的业务需求,不仅表现在新发现的需求上,也表现在对市场变化做出反应的需求上。例如,当软件正在设计和构造的时候,某一个竞争对手发布了一个新的产品,因此,需要在已经计划好的功能上做一些改变。类似地,政府机构或标准制订机构可能会强制推行一项规则或标准,而它可能影响到软件的设计或需求。人们认为,通过在软件开发过程中加入灵活性,敏捷方法使用户能够在开发周期的后期增加或改变需求。
在目前的文献中,有很多敏捷过程的典型方法。每一种方法都基于一套原则,这些原则实现了敏捷方法所宣称的理念(敏捷宣言)。具体方法有以下几种。
极限编程(XP):在下面会对它进行详细描述。它是激发开发人员创造性、使管理负担最小的一组技术。
水晶法(Crystal):它认为每一个不同的项目都需要一套不同的策略、约定和方法论。水晶法正是基于这一理念的一组方法。Cockburn是水晶法的创建者(Cockburn 2002)。他认为,人对软件质量有重要的影响,因而随着开发人员素质的提高,项目和过程的质量也随之提高。通过更好的交流和经常性的交付,软件生产力得以提高,因为它较少需要中间工作产品。
并列争球法(Scrum):该方法由对象技术公司于1994年创建,随后Schwaber和Beedle将它产品化(Schwaber and Beedle 2002)。它使用迭代的方法,其中把每30天一次的迭代称为一个“冲刺”(sprint),并按需求的优先级别来实现产品。多个自组织和自治小组并行地递增实现产品。协调是通过简短的日常情况会议(称为“scrum”)来进行的,就像橄榄球中的“并列争球”(scrum)。
自适应软件开发(ASD):它有6个基本的原则。在自适应软件开发中,有一个使命作为指导,它设立项目的目标,但并不描述如何达到这个目标。特征被视作客户价值的关键点,因此,项目是围绕着构造的构件来组织并实现特征的。过程中的迭代是很重要的,因此“重做”与“做”同样关键,变化也包含其中。变化不被视作改正,而是被视作对软件开发实际情况的调整。确定的交付时间迫使开发人员认真考虑每一个生产的版本的关键需求。同时,风险也包含其中,它使开发人员首先解决最难的问题。
通常,“极限编程”是描述敏捷方法最普遍的概念。实际上,XP是敏捷过程的一种具体形式,提供敏捷方法最一般原则的指导方针。XP的支持者强调敏捷方法的4个特性:交流、简单性、勇气以及反馈。交流是指客户与开发人员之间持续地交换看法;简单性鼓励开发人员选择最简单的设计或实现来处理客户的需要;XP创建者将勇气描述为尽早和经常交付功能的承诺;在软件开发过程的各种活动中,都包含反馈循环。例如,程序员们一起工作,针对实现设计的最佳方式,相互提供反馈;客户与开发人员一起工作,以完成计划的任务。
这些特性都包含在XP的12个实践操作中。
规划游戏:在XP的这一方面,由现场的客户定义价值的含义,以便对于每个需求,可以根据实现该需求所增加的价值对其进行评价。用户就系统应该如何运转来编写故事,然后,开发人员估算实现该故事所必需的资源。这些故事描述所涉及的演员和情节,很像在第4章和第6章定义的用例。每一个故事针对一个需求:只需要两三个句子足够详细地解释需求的价值,以便开发人员指定测试用例,估算实现需求所需的资源。故事编完之后,预期的用户对需求划分优先级,不断地拆分、合并需求,直到就需要什么、什么可测试、利用可用资源能够完成什么这些事项达成一致为止。然后,计划人员生成发布图,将发布的内容和交付的时间记录在文档中。
小的发布:系统的设计要能够尽可能早地交付。功能被分解为若干个小的部分,这样,可以尽早地交付一些功能。然后,在后面的版本中对这些功能加以改进和扩展。这些小的发布需要使用增量或迭代生命周期的阶段化开发方法。
隐喻:开发团队对于系统将如何运行的设想取得一致意见。为了支持这个共同的设想,开发团队选取共同的名字,并就处理关键问题的共同方法达成一致意见。
简单设计:只处理当前的需求,使设计保持简单。这种方法体现这样一个基本思想:对将来的需求进行预测可能导致不必要的功能。如果系统的某个特定部分是非常复杂的,那么开发团队可能要构建一个试验性解决方案(spike)(一个快速、有限的实现)以帮助决定如何继续进行。
首先编写测试:为了确保客户的需要成为开发的驱动力,首先编写测试用例,这是一种强迫客户需求在软件构建之后可以被测试和验证的方法。XP使用两种测试:功能测试和单元测试。功能测试由客户指定,由开发人员及用户测试;而单元测试由开发人员编写和测试。在XP中,功能测试是自动执行的,并且在理想情况下,每天都执行。功能测试被认为是系统规格说明的一部分。在编码前后都要进行单元测试,以验证每一个模块都符合设计规格说明。第8章将详细讨论这两种测试。
重构:随着系统的构建,很可能需求将发生变化。因为XP方法的一个主要特征是只针对当前的需求进行设计,所以,经常出现这样的情况:新的需求迫使开发人员重新考虑他们现有的设计。重构(refactoring)是指重新审视需求和设计,重新明确地描述它们以符合新的现有的需要。有时,重构是指重组(restructure)设计和代码,而不扰乱系统的外部行为。重构是以一系列小的步骤完成的,辅之以单元测试和对编程,用简单性指导工作。我们将在第5章讨论重构的难点。
对编程:如第1章指出的,将软件工程视作艺术和将软件工程视作科学这两种观点之间存在着紧张关系。对编程试图强调软件开发的艺术性这一方面,承认学徒-师父这样的隐喻,对于教会软件开发初学者如何逐步具有熟练开发人员的能力是很有用的。使用一个键盘,两个结成对的程序员,根据需求规格说明和设计开发系统,由一个人负责完成代码。但是,配对是灵活的:一个开发人员在一天中可能与多个伙伴配对。传统的开发方法是个人单独工作,直到他们的代码经过单元测试。第7章会将对编程与传统方法进行比较。
集体所有权:在XP中,随着系统的开发,任何开发人员都能够对系统的任何部分进行改变。在第11章,我们将讨论管理变化过程中的难点,包括当两个人试图同时改变同一个模块的时候引入的错误。
持续集成:快速交付功能意味着可以按日为客户提供可运行的版本,有时甚至可以按小时提供。重点是多个小的增量或改进,而不是从一个修正到下一个修正这样的巨大跳跃。
可以忍受的步伐:疲劳可能产生错误。因此,XP的支持者提出每星期工作40个小时的目标。逼迫程序员投入很长的时间来满足最后期限,就表明最后期限不合理,或者是缺乏满足最后期限的资源。
在现场的客户:理想情况下,客户应该在现场与开发人员一起工作以确定需求,并提供如何对它们进行测试的反馈。
代码标准:很多观察者认为XP和其他敏捷方法提供了不受约束的环境,在其中可以做任何事情。但是实际上,XP倡导清晰的代码标准定义,以利于团队改变和理解他人的工作。这些标准支持其他的实践,例如测试和重构。其结果应该是代码整体看起来就像是由一个人编写的,并且其方法和表述一致。
极限编程和敏捷方法是比较新的方法(补充材料2-2)。其有效性的证据很少,但却呈增长趋势。在后面的章节讨论其相关活动的时候,我们将再次讨论很多敏捷方法和概念,以及它们的实证性评估。
本章出现的过程模型仅仅是实际使用或讨论的模型中的一小部分。其他过程模型可以根据用户、客户和开发人员的需要进行定义和剪裁。正如在补充材料2-3中指出的那样,实际上,我们应该用一组过程模型描述软件开发过程,而不是集中于单个模型或视图。
补充材料2-2 什么时候极限编程显得过于极端/p>
就像大多数软件开发方法一样,敏捷方法也招致了一些批评。例如,Stephens和Rosenberg指出,很多极限编程的实践是相互依赖的,如果其中一个被修改,其他的都会受到影响(Stephens and Rosenberg 2003)。要了解其中的原因,我们假定一些人对于对编程是不满意的。那么,就可能需要更多的协调和文档来解决当人们各行其是时失去的共识。类似地,许多开发人员喜欢在编程之前进行设计。Scrum通过建立每月冲刺来处理这种喜好。Elssamadissy和Schalliol指出,在极限编程中,需求被表示为一系列必须能通过软件审查的测试用例(Elssamadissy and Schalliol 2002)。这种方法可能促使客户代表关注测试用例而不是需求。因为测试用例是需求的详细表述,并且可能是面向解决方案的,所以,将重点放在测试用例上可能会将客户代表的注意力从项目的目标转移开,并且可能导致这样一种情形:系统通过了所有测试,但是却不是客户认为他们应该得到的系统。正像我们将在第5章中看到的,重构可能是敏捷方法的要害,很难做到重做一个系统而不降低体系结构的质量。
补充材料2-3 过程模型的集合
我们在补充材料2-1中看到,开发过程是一个问题求解的活动,但是流行的过程模型很少会包含问题求解。Curtis、Krasner和Iscoe对17个大型项目进行了现场研究,以确定过程模型中应获取哪些问题求解的因素,以帮助我们理解软件开发(Curtis, Krasner and Iscoe 1988)。尤其是,他们考虑了影响项目结果的行为因素和组织因素。他们的研究结果提出了一个关于软件开发层次的行为模型,其中包含5个关键视角:业务环境、公司、项目、开发团队和个人。个人视图提供关于认知和动机的信息,项目和开发团队的视图告诉我们团体动态的相关情况。公司和业务环境提供了可能影响生产率和质量的组织行为的信息。这个模型并不是要替换传统的过程模型,它与传统模型是正交的关系,提供的信息是行为如何影响创建和生产活动,它是对传统模型的补充。
随着开发人员和客户对问题了解的加深,他们把彼此的领域知识、技术和业务结合起来,以得到一个合适的解决方案。通过把开发看作是一组相互协作的过程,我们可以看到学习、技术交流、客户交互和需求协商的效果。不过,当前描述一系列开发任务的模型“对下述问题的分析是没有帮助的:项目成员必须了解多少新信息,如何协商那些有分歧的需求,设计团队如何解决体系结构的冲突以及类似因素对项目内在的不确定性和风险有何影响”(Curtis, Krasner and Iscoe 1988)。然而,当我们引入认知的、 会的、组织的和过程的相关模型时,我们就开始了解瓶颈和低效率的原因。正是这样的认识使得管理人员能够理解和控制开发过程。而通过总体考虑跨越各个模型层的行为,可以了解每个模型对另一个模型因素的效果所产生的影响。
不论使用哪一种过程模型,许多活动都是所有模型所共有的。在后面章节中对软件工程进行探讨的时候,我们将研究每一个开发活动,了解它包含的内容,并找出什么样的工具和技术能够使我们的工作更加有效、生产率更高。
相关资源:城市规划常用软件湘源控规_湘源镇区规划-咨询工具类资源-CSDN文库
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!