1、1第 1 章 软件工程概述计算机软件是整个计算机系统中具体实现各种功能和操作的核心部分。软件工程采用工程的概念、原理、技术和方法来开发和维护计算机软件,将工程管理技术的成功经验和思想与具体的软件开发过程、研究技术相结合,形成一整套适合于计算机软件开发的方法、规范和技术。因此,软件工程这门课程,对于从事软件开发研究的专业人员,特别是高层次的管理、分析、开发人员,显得比以往更加重要。本章主要介绍软件工程的发展背景、软件工程学的范畴、软件工程的基本目标等。1.1 软件发展和软件危机1.1.1 软件的定义和发展自从世界出现第一台计算机到目前,软件的开发与研究经历了几十年的发展。对于计算机软件,有多种不
2、同的定义,但一般可以理解为“软件是能够完成预定功能和性能的可执行的计算机程序和使程序正常执行所需要的数据,加上描述程序的操作和使用的文档”。根据发展历程,可以分为 4 个阶段,如图 1-1 所示。(1)程序设计阶段,约为 20 世纪五六十年代。(2)程序系统阶段,约为 20 世纪六七十年代。(3)软件工程阶段,约为 20 世纪 70 年代以后。(4)面向对象软件工程阶段,约为 20 世纪 80 年代以后。图 1-1 软件的发展软件发展过程最根本的变化体现在以下几个方面:(1)人们改变了对软件的看法。在 20 世纪五六十年代时,程序设计曾经被看做一种任人发挥创造才能的技术领域。当时人们认为,程序
3、运行后只要能在计算机上得出正确的结果,程序的写法可以不受任何约束。随着计算机的使用范围日趋广泛,人们要求这些程序2易懂、易使用,并且容易修改和扩充。于是,程序便从按个人意图创造的“艺术品”转变为能被广大用户接受的工程化产品。(2)软件的需求是软件发展的动力。早期的程序开发只是为了满足开发者自己的需要,这种自给自足的生产方式是其低级阶段的表现。进入软件工程阶段后,软件开发的成果具有社会属性,它要在市场中流通以满足广大用户的需要。(3)软件工作的考虑范围从只顾及程序的编写扩展到涉及整个软件生存周期。1.1.2 软件危机过程20 世纪 60 年代后期,随着计算机应用的日益普及,软件数量急剧膨胀,众多
4、因素导致在软件的开发过程中,所开发的软件产品质量低下,众多软件无法满足用户需求,软件的可维护性差,以至于问题不断堆积,形成日益尖锐的矛盾,通常人们将这些现象通称为“软件危机”。为此,NATO 的一个研究小组于 1967 年提出了“软件工程”概念,并于1968 年北大西洋公约组织在联邦德国召开的计算机科学家国际会议上得到签署,与会人员得出结论:软件工程应当使用已经建立的工程科学的基本原理和范型来解决“软件危机”。软件工程学由此产生。1. 软件危机的主要表现软件危机是指在计算机软件的开发和维护过程中所遇到的一系列严重问题。这些问题绝不仅仅是“不能正常运行的”软件才具有的,实际上几乎所有软件都不同程
5、度地存在这些问题。概括地说,软件危机包含下述两方面的问题:如何开发软件来满足对软件的日益增长的需求;如何维护数量不断膨胀的已有软件。具体地说,软件危机主要有下述一些表现形式:(1) 对软件开发成本和进度的估计常常很不准确。实际成本比估计成本有可能高出一个数量级,实际进度比预期进度拖延几个月甚至几年的现象并不罕见。这种现象降低了软件开发组织的信誉。而为了赶进度和节约成本所采取的一些权宜之计又往往降低了软件产品的质量,从而不可避免地会引起用户的不满。(2) 用户对“已完成的”软件系统不满意的现象经常发生。软件开发人员常常在对用户要求只有模糊的了解,甚至对所要解决的问题还没有确切认识的情况下,就仓促
6、上阵,匆忙着手编写程序。软件开发人员和用户之间的信息交流往往很不充分,“闭门造车”必然导致最终的产品不符合用户的实际需要。(3) 软件产品的质量往往靠不住。软件可靠性和质量保证的确切的定量概念刚刚出现不久,软件质量保证技术(审查、复审和测试)还没有完全地应用到软件开发的全过程中,这些都导致软件产品发生质量问题。(4) 软件常常是不可维护的。很多程序中的错误是非常难改正的,实际上不可能使这些程序适应新的硬件环境,也不能根据用户的需要在原有程序中增加一些新的功能。“可重用的软件”还是一个没有完全做到的、正在努力追求的目标,人们仍然在重复开发类似的或基本类似的软件。(5) 软件通常没有相关的文档资料
7、。计算机软件不仅仅是程序,还应该有一整套文档资料。这些文档资料应该是在软件开发过程中产生出来的,而且应该是“最新式的”(即和3程序代码完全一致的)。软件开发组织的管理人员可以使用这些文档资料作为“里程碑”,来管理和评价软件开发工程的进展状况;软件开发人员可以利用它们作为通信工具,在软件开发过程中准确地交流信息;对于软件维护人员而言,这些文档资料更是至关重要、必不可少的。缺乏必要的文档资料或者文档资料不合格,必然给软件开发和维护带来许多严重的困难和问题。(6) 软件成本在计算机系统总成本中所占的比例逐年上升。由于微电子学技术的进步和生产自动化程度不断提高,硬件成本逐年下降,然而软件开发需要大量人
8、力,软件成本随着通货膨胀以及软件规模的不断扩大和数量的增加而持续上升。美国在 1985 年软件成本大约已占计算机系统总成本的 90。(7) 软件开发生产率提高的速度,远远跟不上计算机应用迅速普及深入的趋势。软件产品“供不应求”的现象使人类不能充分利用现代计算机硬件提供的巨大潜力。以上列举的仅仅是软件危机的一些明显的表现,与软件开发和维护有关的问题远远不止这些。2. 产生软件危机的原因在软件开发和维护的过程中存在这么多严重问题,一方面与软件本身的特点有关,另一方面也和软件开发与维护的方法不正确有关。软件不同于硬件,它是计算机系统中的逻辑部件,而不是物理部件。在写出程序代码并在计算机上试运行之前,
9、软件开发过程的进展情况较难衡量,软件开发的质量也较难评价,因此管理和控制软件开发过程相当困难。此外,软件在运行过程中不会因为使用时间过长而被“用坏”,如果运行中发现错误,很可能是遇到了一个在开发时引入的在测试阶段没能检测出来的故障。因此,软件维护通常意味着改正或修改原来的设计,这就在客观上使得软件较难维护。软件不同于一般程序,它的一个显著特点是规模庞大。例如,美国四代宇宙飞船的软件规模呈指数增长,20 世纪 70 年代末穿梭号宇宙飞船的软件包含 4000 万行目标代码。假设一个人一年可以开发出一万行的程序,为了开发一个 4000 万行的软件,是否集中 4000人的力量一年就可以完成呢?绝对做不
10、到!因为代码长度增加了 4000 倍,程序复杂程度的增加远远超过 4000 倍。而且如何保证每个人完成的工作合在一起确实能构成一个高质量的大型软件系统,更是一个极端复杂和困难的问题,不仅涉及许多技术问题,诸如分析方法、设计方法、形式说明方法、版本控制等,更重要的是必须有严格而科学的管理。软件本身独有的特点确实给开发和维护带来一些客观困难,但是人们在开发和使用计算机系统的长期实践中,也确实积累和总结出了许多成功的经验。如果坚持不懈地使用经过实践考验和证明是正确的方法,许多困难是完全可以克服的。过去也确实有一些成功的范例。但是,目前相当多的软件专业人员对软件开发和维护还有不少糊涂观念,在实践过程中
11、或多或少地采用了错误的方法和技术,这可能是使软件问题发展成软件危机的主要原因。与软件开发和维护有关的许多错误认识和做法的形成,可以归因于在计算机系统发展的早期软件开发的个体化特点。错误认识和做法主要表现为忽视软件需求分析的重要性,认为软件开发就是写程序并设法使之运行,轻视软件维护等。4事实上,对用户要求没有完整准确的认识就匆忙着手编写程序是许多软件开发工程失败的主要原因之一。只有用户才真正了解他们自己的需要,但是许多用户在开始时并不能准确具体地叙述他们的需要,软件开发人员需要做大量深入细致的调查研究工作,反复多次地和用户交流信息,才能真正全面、准确、具体地了解用户的要求。对问题和目标的正确认识
12、是解决任何问题的前提和出发点,软件开发同样也不例外。急于求成,仓促上阵,对用户要求没有正确认识就匆忙着手编写程序,这就如同不打好地基就盖高楼一样,最终必然倒塌。做好软件定义阶段的工作,是降低软件开发成本和提高软件质量的关键。如果软件开发人员在定义阶段没有正确全面地理解用户需求,直到测试阶段或软件交付使用后才发现“已完成的”软件不完全符合用户的需要,这时再修改就为时已晚了。严重的问题是,在软件开发的不同阶段进行修改需要付出的代价是很不相同的,在早期引入变动,涉及的面较少,因而代价也比较低;而在开发的中期软件配置的许多成分已经完成,引入一个变动要对所有已完成的配置部分都做相应的修改,不仅工作量大,
13、而且逻辑上也更复杂,因此付出的代价剧增;在软件“已经完成”时再引入变动,当然需要付出更高得多的代价。根据美国一些软件公司的统计资料,在后期引入一个变动比在早期引入相同变动所需付出的代价高 23 个数量级。通过上面的论述不难认识到,轻视维护是一个最大的错误。许多软件产品的使用寿命长达 10 年甚至 20 年,在这样漫长的时期中不仅必须改正使用过程中发现的每一个潜伏的错误,而且当环境变化时(如硬件或系统软件更新换代)还必须相应地修改软件以适应新的环境,特别是必须经常改进或扩充原来的软件以满足用户不断变化的需要。所有这些改动都属于维护工作,而且是在软件已经完成之后进行的,因此维护是极端艰巨和复杂的工
14、作,需要花费很大代价。统计数据表明,实际上用于软件维护的费用占软件总费用的5570。软件工程学的一个重要目标就是提高软件的可维护性,减少软件维护的代价。了解产生软件危机的原因,澄清错误认识,建立起关于软件开发和维护的正确概念,还仅仅是解决软件危机的开始,全面解决软件危机需要一系列综合措施。3. 缓解软件危机的途径软件开发不是某种个体劳动的神秘技巧,而应该是一种组织良好,管理严密,各类人员协同配合,共同完成的工程项目。必须充分吸取和借鉴人类长期以来从事各种工程项目所积累的行之有效的原理、概念、技术和方法,特别要吸取几十年来人类从事计算机硬件研究和开发的经验教训。应该推广使用在实践中总结出来的开发
15、软件的成功的技术和方法,并且研究探索更好更有效的技术和方法,尽快消除在计算机系统早期发展阶段形成的一些错误概念和做法。应该开发和使用更好的软件工具。正如机械工具可以“放大”人类的体力一样,软件工具可以“放大”人类的智力。在软件开发的每个阶段都有许多烦琐重复的工作需要做,在适当的软件工具辅助下,开发人员可以把这类工作做得既快又好。如果把各个阶段使用的软件工具有机地集合成一个整体,支持软件开发的全过程,则称为软件工程支撑环境。5总之,为了解决软件危机,既要有技术措施(方法和工具),又要有必要的组织管理措施。软件工程正是从管理和技术两方面研究如何更好地开发和维护计算机软件的一门新兴学科。4. 对软件
16、危机的理解由以上的叙述可以得知,由于历史原因,人们提出将已经建立的工程科学的基本原理和范型用于软件开发,借此来解决“软件危机”问题。但是,从目前软件发展的实际情况看,虽然现代软件的开发方法、技术、手段、工具等有了巨大的发展。但从广义上来说,“软件危机”所指的问题并没有解决,有些方面的问题甚至更为严重和突出。由此,我们有必要首先对“危机”的概念进行一定的考察、定义和重新认识。据韦氏字典中对危机的定义为“任何事情中的一个转折点,决定性的或危急的时刻,阶段或事件”。例如金融危机、历史上的物理学危机等,他们均符合对危机的定义。但是对于软件而言,没有所谓的转折点,没有“决定性时刻”。“软件危机”到目前已
17、经出现了四十多年,还将延续下去。由此不得不对“软件危机”的术语进行重新思考和定义。对于这个问题,有学者认为,应该称为软件开发中存在的“慢性的苦恼”。不论如何定义和称呼,可以将“软件危机”理解为泛指在计算机软件开发中所遇到的一系列问题。这些问题不仅局限于那些“不能正确完成功能”的软件,还包括那些与我们如何开发软件,如何维护大量已有软件,如何使软件开发速度与对软件需求的增长相适应等问题。1.2 软件工程学的范畴软件工程学包括软件开发技术和软件工程管理。而软件开发技术又分为软件开发方法学、软件工具、软件工程环境。软件工程管理又分为软件管理学、软件经济学、软件度量学。软件开发方法学:无固定方法结构化的
18、软件开发面向对象的软件开发(软件复用)软件工具:帮助开发软件的软件叫做软件工具,在软件开发的各个阶段都有许多有效的工具,这些工具结合起来构成“软件箱”或“集成工具”。软件工程环境:方法和工具相结合,再加上配套的软、硬件支持就形成环境(Software Engineering Environment 简称 SE2)。软件工程管理:目的是按照进度及预算完成软件开发计划,实现预期的经济效益和社会效益。1.3 软件开发的生命周期计算机软件,从决定进行开发到最终退役所经历的一系列步骤与过程称为软件生命周期。通常将软件生命周期划分为需求分析、规格说明、设计、实现、集成、测试、维护和退役。6传统软件工程中,
19、使用最为普遍的模型之一是“瀑布模型”。这种模型有多种不同形态,但总的来说主要经历了 8 个阶段。虽然这 8 个阶段和任何一个特定的组织所经历的阶段可能不完全一致,但和大多数的实际工作非常接近。这些阶段的名称和基本任务为:(1)需求分析阶段。探究抽象和求精概念,并明确客户的需求。(2)规格说明(分析)阶段。分析客户的需求,形成规格文档。说明“产品要做什么”。这个阶段有时也称为分析阶段。(3)设计阶段。规格说明顺序经历两个设计阶段。第一是结构设计,即把产品由一个整体分解成多个组成部分,称为模块。然后设计各个模块,这个阶段称为详细设计。在此阶段产生“设计文档”,描述“产品是如何做成的”。(4)实现阶
20、段。又可成为“编码阶段”,在这一阶段中,对各部分进行编码和测试。(5)集成阶段。将各组成部分合并成一个整体并做测试。当开发者对产品满意后,就把它交给用户测试(验收测试)。将用户对产品的认可作为这个阶段终止的标志。(6测试阶段。针对不同的开发阶段,软件测试可以分为单元测试、集成测试、系统测试等不同的测试,其目的是及时发现软件开发各个阶段中的错误和问题。(7)维护阶段。维护是指在客户认可产品满足规格文档之后,对软件所做的所有修改。维护包括改正性维护(或软件修正),主要是排除残余的故障,同时不改变规格说明,以及增进性维护(或软件更新),包括修改规格说明,并实现这些修改。而增进性维护又包括两种类型。第
21、一是完善性维护,即用户认为能改善产品功能的修改,如附加功能或降低响应时间。第二是适应性维护,即为适应产品运行环境的改变而做的修改,例如,出现了新的政府法令。研究表明,平均来说,修正性维护大约占维护时间的 17.5,完善性维护占60.5,适应性维护大约占 18。(8)退役:产品退出服务。如果将整个软件开发周期作为一个整体,那么,在软件产品开发的过程中,依据 HP 公司的统计数据,得到各个阶段所花费的比例如图 1-2 所示。图 1-2 软件生命周期各阶段的大致花费比例7由图 1-2 可以看出,维护大约占总的软件费用的 3/4。较新的数据证明,人们已越来越重视维护工作。正因为维护工作非常重要,所以那
22、些能降低维护费用的技术、工具和实践构成了软件工程的主要方面。特别值得注意的是,在进行软件产品开发的过程中,越早发现错误和问题并尽早解决,造成的损失越小,所需要的工作量越少。许多软件开发人员对此认识不足。依据IBM、GET、防御工程以及一些较小的 TRW 工程Boehm,1980。一个故障在不同的阶段进行修复的相对代价如图 1-3 所示。其中用实线表示最适用于与大型工程项目有关的数据,而虚线表示数据适用于较小的工程。图 1-4 描述了在软件生命周期各阶段检测和修正一个故障对应的相对费用,其中用实线表示的每一阶段,是取图 1-3 中的实线相应的点,并按线性刻度标记数据。图 1-3 不同阶段检修故障
23、的相对费用由图 1-4 可见,产品发布后发现并修正一个错误的花费是需求阶段所需花费的 200 倍左右。假设在设计阶段检测和修正一个特定故障要花费 40 美元,则从图 1-4 的实线(19741980 年之间的项目)可以看出,在规格说明阶段检修同样的故障只要花费 20 美元。但在维护阶段,检修故障则要花费 2 000 美元左右。较新的数据显示表明,及时地检测故障在当今更为重要。如图 1-4 所示的虚线显示了在为 IBM 的 AS400 开发系统软件期间检测并修正故障的费用Kan 等,1994。相同的故障在 AS400 软件的维护期间将要花费680 美元。修改一个故障至少意味着要编辑代码、重新编译
24、、重新链接,然后仔细测试;其后,检查所做的修改没有在产品的任何地方产生问题;确保所有相关的文档(包括使用手册)都做了更新;最后,修正后的产品必须交付给用户,重新安装。因此,我们必须在需求分析和规格说明阶段运用故障检测技术。研究表明,在大规模工程中所检测到的所有故障中有 6070属于规格说明故障或设计故障。较新的研究结果更反映出规格说明故障和设计故障占压倒性多数。“审查8(inspection)”是对一个软件组所制定的文档进行仔细的检查。Stephen R.Schach 在他的软件工程著作中提到:“在对为 NASA 无人太阳系空间站编制的 Jet Propulsion laboratory 软件
25、所做的 203 次审查中发现,规格文档中平均每页出现故障 1.9 个,设计文档中平均每页为 0.9 个,而在代码中平均每页只有 0.3 个故障Kelly、 Sherif 和Hops,1992。”因此,改进规格说明和设计技术非常重要,这不仅仅是为了能尽早地发现故障,也因为规格说明故障和设计所占所有故障的比重特别大。通常,将维护费用降低 10,可以使总费用下降约 7;同样,规格说明故障和设计故障减少 16,可以使故障总数降低67。图 1-4 实现描述图 1-3 中实线的各点按线性刻度标记的情况1.4 传统软件工程和面向对象软件工程结构化的程序设计推动了程序设计风格从“追求技巧与效率”到“清晰第一,
26、效率第二”的转变,从而提高了程序的易读性和可靠性。形成了结构化的软件开发范型,即传统软件工程或经典软件工程。自 1967 年以来,人们提出了各种各样的技术来帮助解决软件危机问题。在大约19751985 年间,随着结构化范型的发展,这一问题有了重大的突破。构成结构化范型的技术包括结构化分析、组合结构化设计、结构化编程和结构化测试。这些技术在最初运用时似乎极具前景,但事实证明,它在两个方面很不成功。首先,这些技术有时不能应付产品规模的不断增大。也就是说,结构化技术处理 5 000 行或 50 000 行代码时是有效的。然而,当今的软件成品,500 000 行代码并不算大,5 000 000 或更多
27、行代码也常常出现。结构化技术通常不能应付当今的大规模软件产品。维护阶段是结构化范型不能满足人们期望的第二个方面。结构化范型在 20 年前就得以发展的主要驱动力是,软件预算中通常有 34 是用于维护。但遗憾的是,结构化范型没有解决这一问题,今天仍有许多组织在维护上花的时间和努力高达 80(Yourdon,1992)。9引入结构化范型带来的主要改进是在软件工业上。在使用结构化范型之前,大多数的软件组织都不使用任何特定的技术,每个人都以自己的方式工作。结构化范型在工业领域的运用是软件工程被大规模采纳的主要原因。不过结构化范型并没有解决软件产品的所有问题。结构化范型只获得有限成功的原因是,结构化技术要
28、么面向行为,要么面向数据,但没有既面向数据又面向行为的。软件的基本组成部分包括产品的行为和这些行为操作的数据。典型的开发原理如图 1-5a 所示。面向对象的程序设计较好地的实现了“解空间”与“问题空间”的一致性。“对象消息”的机制取代了“数据结构算法”的思路。面向对象的范型把数据和行为看成同等重要。看待一个对象的一个极其简洁的方法是将对象视作一个融合了数据及在其上操作的行为的、统一的软件组件。面向对象范型具有很多优势:()有效地降低了软件的复杂性,简化了软件的开发。()有利于维护。修改程序限于对象本身,因而导致软件故障的机会大大减少,令大型软件的维护更快、更简单。传统软件工程包括:软件分析总体
29、设计详细设计面向过程的编码测试,面向对象软件工程包括:软件分析与对象提取对象详细设计面向对象的编码测试。这两种方法之间看上去区别很小。然而,它们的实现方式有着本质的区别和不同。关键在于对象的实现方式,特别是关于一个对象的数据元素是如何存储的细节对外界是封闭的。这是“信息隐藏”的一个实例。因此,在图 1-5b 显示的银行账户中,软件产品的其余部分知道,在银行账户对象中有一个账目余额属性,但不知道账目余额的格式。即对象的外部不知道账目余额是用整数还是用浮点数实现的,也不知道它是不是某个更大结构的一个组成部分。这个环绕在对象周围的“围栏”在图 1-5b 中用实线表示,以表达面向对象范型的实现形式。与
30、之对照,图 1-5a 中账目余额的周围是虚线,表示在使用结构化范型实现时,账目余额的所有细节为各模块所知,因此,任何一个模块都可改变账目余额的值。账 目 余 额存 款取 款计 算 余 额账 目余 额取 款存 款计 算 余 额取 款 消 息进 行 计 算 余 额 消 息存 款 消 息a) b)图 1-5 使用结构化范型和面向对象范型的比较现以图 1-5b 为例说明面向对象的实现:如果一个客户在账户中存 10 美元,于是便有条消息送到相应的存款行为(方法),让它在账目余额数据元素(实例变量)中增加 10 美元。存款属于银行账户对象,它知道账户余额实例变量的实现方法,这由对象内部的虚线表示。10但任
31、何在对象之外的实体完全不需要知道这些。在图 1-5b 中,三种方法将“账目余额”和软件的其他部分隔开,这一事实代表了这种知识的局部化。面向对象范型的优势主要体现在维护阶段。首先,假定银行业务软件是用结构化范型构造的,假如账目余额的表示法以整型改为浮点数,那么该产品中与账目余额有关的所有部分均应改变,而且这些变化必须保持一致。相比之下,如果是使用面向对象的范型,则只需改变银行账目对象本身。产品中的其他部分不知道账目余额是怎样实现的,所以没有哪个部分能访问账目余额。于是,该产品中任何其他的部分均不需要被改变。因此,面向对象的范型使维护更快、更容易,同时,也大大降低了产生递归故障的可能性。面向对象的
32、范型除了维护方面的优势外,还使开发更加容易。在多数情况下,一个对象都有一个物理上的对应物,例如,银行账户对象对应于实际银行的手写账目。模型化在面向对象的范型中起了主要的作用。软件产品中的对象和现实世界的同等对应物之间的密切对应关系,促进了更优化的软件开发。还可以从另一个角度考察面向对象范型的优点。设计良好的对象是一个独立的单元。如上所述,对象由数据及在其上执行的操作组成。如果所有施加于对象数据的行为都包含在对象中,则就可将该对象视为一个概念上独立的实体。现实世界中某个事物通过对该对象的模型化后,关于该事物的一切方面均可在该对象中找到。这种概念上的独立性有时称为“封装”。但还有另一种形式的独立性
33、,即物理独立性。在一个设计良好的对象中,信息隐藏保证了实现的细节对对象以外的封闭。惟一允许的通信形式是向该对象发送一条消息,让它执行特定的行动。行动执行的方式完全是对象自身的责任。由于这个原因,面向对象的设计有时被称为“责任驱动的设计 Wirfs-Brock、Wilkerson 和 Wiener,1990,或“承包制设计”Meyer 1992a。使用结构化范型所构造的产品基本上是单个单元,这就是结构化范型在运用于大型产品时不太成功的原因之一。相反,当面向对象的范型被正确使用时,最终的产品由许多较小的、基本上独立的单元组成。面向对象的范型降低了软件产品的复杂性,简化了开发和维护。面向对象范型的另
34、一个积极的特征是它促进了重用,因为对象是独立的实体,所以它们可以用在以后的产品中。对象的重用降低了开发维护的时间和费用。在利用面向对象的范型时,软件生命周期必须做适当修改,表 1-1 列出了结构化范型和面向对象范型的软件周期。为评价两者间的区别,首先考虑结构化范型的设计。在结构设计子阶段中,产品被分解为多个部分,称为模块。然后,在详细设计子阶段设计每个模块结构的算法。最后在实现阶段,这些模块分别被实现。如果是采用面向对象的范型,则在分析阶段中有一个确定对象的步骤。因为对象是一种模块,所以结构化设计是在面向对象范型的分析阶段执行的。因此,面向对象的分析阶段比结构化范型相应的规格说明(分析)阶段范
35、围更广泛。这两种范型之间的不同产生了重要的结果。当使用结构化范型时,分析阶段和设计阶段之间过渡太快。毕竟,规格说明阶段的目标是决定产品做什么,而设计阶段的目的是如何做。相比之下,当使用面向对象的分析时,对象在一开始便进入了生命周期。对象在分析阶段抽取,在设计阶段设计,在实现阶段编码。因此,面向对象范型是一种集成的方法,11从一个阶段向另一个阶段的过渡比结构化范型平滑得多,从而降低了开发过程中的故障数目。表 1-1 两种软件开发方法生命周期的比较结构化软件开发阶段 面向对象软件开发阶段需求分析阶段 需求分析阶段规格说明阶段(以结构化方法与技术进行描述) 规格说明阶段(面向对象方法与技术进行描述,
36、同时辅之以结构化方法与技术)结构化概要设计阶段详细设计阶段面向对象设计阶段实现阶段 面向对象实现阶段集成阶段 集成阶段维护阶段 维护阶段退役 退役1.5 软件的特点曾经有人在谈论战争时讲过“战争的规律这是任何指导战争的人不能不研究和不能不解决的问题”。同样,对于任何从事软件开发和指导软件开发的人和组织而言,首先要对于软件的规律、软件的特点进行必要的研究和了解。归纳起来,软件具有以下一些主要特点:(1)软件是一种逻辑实体,而不是具体的物理实体。因此,它具有抽象性。(2)软件的生产与硬件不同,软件是由开发或工程化而形成的,它没有明显的制造过程。对软件的质量控制,必须立足于软件开发方面。软件成为产品
37、之后,其制造只是简单的复制而已。 (3)任何机械、电子设备在运行和使用过程中,其失效率大致遵循如图 1-6 所示的 U 型曲线(即浴盆曲线)。软件的情况与此不同,它不存在磨损和老化问题。然而,它存在退化问题,设计人员必须多次修改(维护)软件。图 1-7 给出了软件故障率的理想曲线,图 1-8给出了实际的软件故障率曲线。故障率时 间0 t12图 1-6 硬件的故障率曲线示意图图 1-7 软件的理想故障曲线故障率0时 间t理 想 曲 线实 际 曲 线由 于 负 作 用 造 成 的故 障 率 提 高图 1-8 软件的实际故障率曲线(4) 软件的开发和运行往往受到计算机系统的限制,对计算机系统有着不同
38、程度的依赖性。为了解除这种依赖性,在软件开发中提出了软件移植的问题。(5) 迄今为止,虽然有许多软件工具能够帮助我们自动生成一些软件代码、结构和框架,但是总体来说,软件的开发尚未完全摆脱手工的方式。(6) 软件本身是复杂的。软件的复杂性可能来自它所反映的实际问题的复杂性,也可能来自程序逻辑结构的复杂性。(7)软件的成本相当昂贵。软件的研制工作需要投入大量的、复杂的、高强度的脑力劳动,它投入的成本是比较高的。(8)相当多的软件工作涉及社会因素。许多软件的开发和运行涉及机构设置、体制运作及管理方式等问题,甚至涉及人们的观念和心理,这些因素直接影响到项目的成败。(9)从市场上买到的软件,它本身就是一
39、个完整的软件,而不能作为构件再组装成新的程序。但目前已有大量支持“软件复用”的软件和中间件作为相对独立的构件。随着软件的发展,以上这些特点也会发生相应的变化,这就要求我们不断研究和适应软件新的变化和特点,随时了解和掌握软件发展新规律。131.6 软件工程的基本目标1.软件工程项目的基本目标组织实施软件工程项目是为了获得项目的成功,即达到以下几个主要的目标: 付出较低的开发成本。 达到预期的软件功能。 取得较好的软件性能。 使开发的软件易于移植。 需要较低的维护费用。 能按时完成开发工作,及时交付使用。在项目的实际开发中,使以上几个目标都达到理想的程度往往是非常困难的。2.软件工程的原则软件工程
40、基本目标适用于所有软件工程项目。为达到这些目标,在软件开发过程中必须遵循下列软件工程原则。(1)抽象:抽取事物最基本的特性和行为,忽略非基本细节。采用分层次抽象,自顶向下、逐层细化的办法控制软件开发过程的复杂性。(2)信息隐蔽:将模块设计成“黑箱”,实现细节隐藏在模块内部,不让模块的使用者直接访问。这就是所谓信息封装(使用与实现分离)的原则。使用者只能通过模块接口访问模块中封装的数据。(3)模块化:模块是程序中在逻辑上相对自主的成分,是独立的编程单位,应有良好的接口定义,如 C 语言程序中的函数过程、 C+语言程序中的类。模块化有助于信息隐蔽和抽象,有助于表示复杂的系统。(4)局部化:在一个物
41、理模块内集中逻辑上相互关联的计算机资源,保证模块之间有松散的耦合,模块内部有较强的内聚。这有助于控制各个模块的复杂性。(5)确定性:软件开发过程中所有概念的表达应是确定的、无歧义的、规范的。这样有助于人们在交流时不会产生误解、遗漏,保证整个开发工作的协调一致。(6)一致性:整个软件系统(包括程序、文档和数据)的各个模块应使用一致的概念、符号和术语;程序内、外部接口应保持一致;软件同硬件、操作系统的接口应保持一致;系统规格说明与系统行为应保持一致;用于形式化规格说明的公理系统应保持一致。(7)完备性:软件系统不丢失任何重要成分,可以完全实现系统所要求的功能。为了保证系统的完备性,在软件开发和运行
42、过程中需要严格的技术评审。(8)可验证性:开发大型的软件系统时需要对系统自顶向下、逐层分解。系统分解应遵循使系统易于检查、测试、评审的原则,以确保系统的正确性。除上述原则外,在现代软件开发过程中,还需特别注意的一个原则是事物分离原则(Principle of Separation of Concerns)。它强调分析模型和设计模型应该分别建立,分析模型用于捕捉事物的本质或逻辑的需求,不考虑基于实现的系统需求。而设计模型则以考虑描述在某一特定的实现环境下如何建立一个特定的软件系统为主要任务。使用一致性、完备性和可验证性的原则可以帮助开发者设计一个正确的系统。随着计算机技术和理论的发展,软件工程理
43、论和应用也在不断的发展中。14小结本章对软件工程的发展过程及背景做了一些介绍,对软件工程的一些基本概念、特点以及传统和面向对象软件工程生命周期进行了讨论,最后简述了软件工程的基本目标。通过对本章内容的学习,应能对软件工程的基本概念、方法、原则有一个总体认识和了解,为进一步学习后续章节的课程打下基础。习题1. 计算机软件具有哪些共同特点?它们和硬件的主要区别有哪些?2. 什么是软件生命周期?面向对象与传统软件工程有何相同之处?3. 软件工程过程包含哪几种基本活动?P、D、C 、A 各代表什么意思?4. 简述软件生存周期的各个环节及各环节的主要内容。5. 软件危机主要包含哪些表现?结合自身实际,谈谈你对软件危机的认识和体会。6. 软件工程学的范畴指的是什么?它包含哪些内容?7. 软件工程的基本目标是什么?有何措施和方法尽可能达到理想的程度?8. 软件生命周期各阶段的大致花费比例是多少?对于从事软件开发有何参考意义?9. 从图 1-3 和图 1-4 中能够得到什么启发?10. 认真比对图 1-6、图 1-7 和图 1-8,加深理解硬件与软件的本质区别。11. 简述软件工程原则。