1、11第1章 软件工程导论第1章 软件工程导论业余软件工程师总在寻找奇迹用某种惊人的方法或工具来让软件开发变得轻而易举,但职业软件工程师都知道不存在这种灵丹妙药。摘自面向对象分析和设计,Grady Booch软件工程这一术语产生于1968年,当时及时地在预算内开发出高质量软件的技术还是一片空白,软件工程一词因此应运而生。当时软件开发者无法制定具体目标,无法预测实现目标所需的资源,也无法实现客户的期望。他们通常承诺的是给用户摘月亮,而制造的却是登月车,最后交付的却是一副方形车轮,这与目标相去甚远。软件工程的重点既在软件,也在工程。一个工程师应该能够在一定时间和预算内,通过使用和集成构件,来构造高质
2、量软件产品。工程师通常面临的问题是问题定义不清和解决方案不全,不得不依靠实验方法来评估解决方案。在飞机设计和桥梁建设等应用领域工作的工程师们已成功地迎接了类似的挑战,而软件工程师们却没那么幸运和成功。在指定时间内构造和交付复杂软件系统的问题,一直以来都得到了人们积极的探讨和研究。一切的一切,包括从客户(“我问你,我为什么不能花50美元得到月亮”)到软件中的“软”的成分(“要是我能加上最后那个特性”),都被归咎于该学科太年轻。问题究竟是什么?复杂性和变化有用的软件系统通常是复杂的。为了有用,它们必须随着终端用户需求和目标环境的变化而变化。在本书中,我们描述了为了征服复杂且不断变化的软件系统方法,
3、即面向对象技术。本章中,我们提供了采用面向对象技术的依据,定义了贯穿全书的基本概念。1.1 导言:软件工程的失误看看下面的例子Neumann, 1995: 1900年错误1992年,来自明尼苏达州怀俄明的玛丽收到一份幼儿园的入园通知,她当时是104岁。 闰年错误1988年2月29日,一家超市因出售过期一天的肉而被罚款1000美元。因为在肉的标签上打印保质期的计算机程序没有考虑到1988年是闰年。 接口误用1990年4月10日,在伦敦地铁运营过程中,司机还没上车,地铁列车就驶离车站。当时司机按了启动键,正常情况下如果车门是开着的,系统就应该可以阻止列车起动。当时的问题是司机离开了列车去关一扇卡着
4、的门,但当门终于关上时,列车还没有等到司机上车就开动了。 安全问题软件工程学院的CERT组(Computer Emergency Response Team,计算机紧急反应小组)是一个政府资助的组织,用来协助社区处理安全事件、突发事件和安全技能方面的问题。美国报道的CERT的安全事件从1990年的252件增加到2000年的21756件,而到2001年已增加到了40000多件。 拖延和超支在1995年,由于新丹佛尔国际机场自动行李系统的错误,造成旅客行李箱的损坏。机场则被迫推迟16个月再开放,且大部分采用手工行李系统,产生32亿美元超支。 拖延和超支(2)2002年的Swanick空运控制系统,
5、包括英格兰和威尔士全部空运线路。在系统交付时,已延期6年且严重超支(实际花费6.23亿英傍,原计划花费3.5亿英镑),其中两次主要的系统升级是在运输操作员培训已经开始后才交付的。 按期交付1984年,经过18个月的开发,一个耗资2亿美元的系统交付给了威斯康星州的一家健康保险公司。但是该系统无法正常工作,只好追加了6千万美元,又花了3年才解决了问题。 不必要的复杂性麦克道尔道格拉斯的C-17货机因为控制系统的软件问题,而超支5亿美元。C-17含有19台机载计算机,80个微处理器以及6种不同的编程语言。上述各种失误的产生都与软件问题有关。有时,开发者没有考虑到偶发事件(如一个人的年龄超过100岁,
6、影响保质期的闰年)。有时,开发者没有考虑到用户主动误用系统(按下按钮、使用网络软件的安全孔)。还有些系统失误的情形是由于管理失误(拖延和超支交付、按期交付不正确的系统以及不必要的复杂度)造成的。软件系统的开发是一个复杂的创造过程。软件系统需要完成多种功能;构建软件系统需要达到许多不同目标,这些目标通常还会相互冲突。软件系统包含许多构件,这些构件是定做的且本身就很复杂。同时,不同领域的人参与了这些构件的开发,这也造成了开发过程的复杂性。开发过程和软件生命周期通常是以年计数的。而且,任何一个人都很难完全理解复杂系统。有很多系统,即使处在开发阶段,也是很难被理解的,以致这些系统最终难以完成而成为“空
7、想件”(vaporware)。软件开发项目要不断变化。因为需求是复杂的,当发现错误、当开发者能更好地理解其应用之后,需求就需要不断被更新。如果一个项目被开发多年,可能出现的问题是人员流动大,这就需要不断对人员进行培训。通常,技术变化的周期比项目周期短。软件项目经理普遍假设所有变化已经得到处理并且需求已经确定,这可能导致开发出不正确的系统。在下一节中,我们将提出一种高层次软件工程视点。我们从科学、工程学以及知识获取和形式化等方面描述软件工程。在第1.3节中,我们更详细地描述了本书所用的主要术语和概念。在第1.4节中,我们对软件工程的开发活动提出了总体看法。在第1.5节中,我们提出了对软件工程管理
8、活动的总体看法。1.2 什么是软件工程软件工程是一种建模活动。软件工程师通过建模来处理复杂性,以做到每次只专注于相关联的细节而忽略其他一切。在开发过程中,软件工程师构建许多不同的系统模型以及应用域模型。软件工程是一种解决问题的活动。模型用于寻找一种可接受的解决问题的方法。这 种寻找方法受实验的驱动。软件工程师没有无限可用的资源,并且会受到预算和提交的 最后期限的限制。由于缺乏基本理论,他们通常得依靠实验方法来评价各种可选方案的 优点。软件工程是一种知识获取的活动。在对应用域和解决方案域进行建模时,软件工程师收集数据,将这些数据转化为信息,并将这些信息形式化为知识。对知识的获取不是线性的,因为单
9、个多余数据就能让整个模型变得无效。软件工程是一种受软件工程原理指导的活动。在获取有关系统或其应用域的知识并做出决策的过程中,软件工程师还需要捕捉到做决策的环境,以及这些决策背后的原理。表示为一组问题模型的软件工程原理信息,可使软件工程师能够在重审一个决策时,理解某种提议改动的含义。在本节中,我们更详细地从建模、问题求解、知识获取和基本原理等角度描述了软件工程。在这些活动中,软件工程师还受到人力、时间和预算的制约。此外,我们假设变化随时会发生。1.2.1 建模科学的目的是描述和理解复杂系统,比如一个原子系、一个人类社会或一个太阳系。通常,人们将自然科学和社会科学相区分,将这两者作为两种主要体系对
10、待。自然科学的目的是理解自然及其子系统。自然科学包括诸如生物学、化学、物理学和古生物学等学科。社会科学的目的是理解人类。社会科学包括心理学和社会学。还有一种系统,我们称之为人工系统。人工系统包括诸如航天飞机、航班预订系统、股票交易系统。Herbert Simon杜撰了一个词汇人工科学(science of artificial)来描述处理人工系统的科学Simon,1970。自然科学和社会科学已经出现了许多世纪了,而人工科学才出现不久。人工科学的典型实例,如计算机科学,就是一种理解计算机系统的科学,该科学在20世纪才诞生。很多已经成功运用于自然科学和人文科学的方法,也可以运用于人工科学中。通过了
11、解其他科学,我们就能够了解关于人工科学方面的更多知识。科学的基本方法之一是建模。一个模型是对一个系统的抽象表示。这种表示使我们能够回答关于系统的问题。在处理太大、太小、太复杂或第一手亲历代价太高的系统时,模型是非常有用的。模型也使我们能够想象和理解那些已经不复存在的系统,或那些被认为存在但未经证实的系统。化石生物学家们出土了一些恐龙的骨头和牙齿,没人见过这些恐龙。利用一些骨头残片,他们依照解剖学的规律,重新构造了恐龙模型。他们发现的骨头越多,就越清楚这些骨头是如何连接起来的,也就越相信他们构建的模型与原始恐龙相符。如果他们发现了足够数量的骨头、牙齿和爪子,他们几乎就可以确定其模型准确地反映了事
12、实,而且,他们可以推测找不到的部分。例如,腿通常是成对的。如果找到了左腿,右腿没有被找到,那么骨头生物学家也很清楚没找到的腿应该是什么样子以及如何连接到模型身上。这就是一个不复存在的系统建模的例子。今天的高能物理学家们也处在一个与已经找到大部分恐龙骨头的化石生物学家相类似的位置。物理学家们也正在构建一个物质与能量以及它们如何在最基本的亚原子层结合的模型。在多年使用粒子加速器进行实验之后,高能物理学家们已经有了足够的自信:他们构建的模型能反映现实,而且那些没有被找到的部分能够与所谓的标准模型相吻合。这是对人们假设存在的一个系统建模的一个实例。两类系统建模者,化石生物学家们和高能物理学家们,他们研
13、究的是两种实体:现实生活系统,即通过一系列现象观察到的系统;应用域模型,即表达为一组相互依存的概念。这里的现实世界系统是一只恐龙或亚原子微粒。应用域模型是对现实世界系统中那些与在研问题相关的方面进行的描述。软件工程师与化石生物学家和高能物理学家面临着类似的挑战。首先,软件工程师需要理解一个系统的运行环境。对于一个列车交通控制系统,软件工程师需要了解列车的信号程序。对于一个股票交易系统,软件工程师需要了解交易规则。软件工程师不需要成为一个完全合格的列车调度员或股票经纪人;他们只需要了解与系统有关的应用域中的概念。换句话说,他们需要构建一个应用域模型。其次,软件工程师需要理解他们能够构建的系统,并
14、能评估不同的解决方案和其他可替换的方案。许多系统都过于复杂,任何个人都无法全部理解,而且许多系统的构建是十分昂贵的。要解决这些难题,软件工程师要描述他们所研究的一些可选系统的某些重要方面。换句话说,他们需要构建一个解决方案域模型。面向对象方法将应用域与解决方案域建模活动合二为一。首先,将应用域建模为一组对象和关系,接着这一模型被系统用来表示它所处理的现实世界中的概念。一个列车交通控制系统包括列车对象,表示该系统监控的列车。一个股票交易系统包括代表股票买卖的交易对象。其次,解决方案域的概念也被建模为对象。用来描绘一列列车或者一次经济交易的语句行就是对象,这些对象是解决方案域的一部分。面向对象方法
15、的思想是:解决方案域模型就是应用域模型的一种转化。开发软件就转化为找出一个解决最终用户问题的系统并将之描述为模型集合。我们将在第2章中更详细地描述建模以及一些对象的概念。1.2.2 问题解决工程是一种解决问题的活动。工程师通常在资源有限和知识不完备的情况下,通过尝试和失败、通过实验评估各种可供选择的方法,寻求解决问题的合适方法,用最简单的形式表述问题与解决方案,工程方法包括以下5步:1明确问题;2分析问题;3寻找解决方案;4选定合适的解决方案;5详细说明解决方案。软件工程是一种工程活动,不是算法活动。软件工程需要试验、标准设计方案的复用、对系统的增量评估以便找到一个客户能接受的方案。面向对象的
16、软件开发通常包括5种开发活动:需求获取、分析、系统设计、对象设计和实现。在需求获取和分析阶段,软件工程师与客户把问题明确化并构建问题域模型。需求获取和分析对应于工程方法的第1步和第2步。在系统设计过程中,软件工程师分析问题,把它分成小块,并选择一些总体策略来设计系统。在对象设计过程中,开发者为每一小块选择一些详细的解决方案,并且最终选择一种最合适的方案。系统设计和对象设计用于产生解决方案域模型。系统设计和对象设计对应于工程方法的第3步和第4步。在实现阶段,软件工程师通过把解决方案域模型转换为可执行表达来实现系统,实现对应于工程方法的第5步。软件工程不同于其他科学的是,在问题解决过程中,应用域和
17、解决方案域还在发生变化。软件开发还包括旨在评价各种模型预算的活动。在分析审查时,应用域模型将与客户实际情况相对比,客户实际情况也可能因为建模而变化。在设计审查时,解决方案域模型要参照项目目标进行评估。在测试过程中,系统的验证要与解决方案域模型进行对比,解决方案域模型可能因为新技术的使用而进行了修改。在项目管理中,经理们将其开发进程模型(即项目进度和预算)与实际情况(即提交的工作产品和使用的资源)相对比。1.2.3 知识获取软件工程师和经理们常犯的错误是,认为开发一个系统所需的知识获取是线性的。不仅软件经理们犯此类错误,其他领域的人也可能犯此类错误。在17世纪,出版了一本书,该书试图在6小时内将
18、所有德国诗歌用像漏斗一样的工具灌入学生头脑。使用漏斗学习的想法是基于我们的头脑如同一个桶的假设,这个桶最开始是空的,可以用线性的方法装满。学习材料通过我们的知觉进来,积聚起来并被我们消化。Popper把这种线性的知识获取模式称为“大脑桶式理论”。在这一理论的诸多错误中(见Popper, 1992描述),有一种错误就是认为知识是由可装在桶里的东西构成的:即,桶越满,我们的知识越多。事实上,知识获取是一个非线性的过程。对理解一个系统而言,一条新信息的获得就可能使我们为了理解系统已获取的所有知识变得无效。即使我们已经在文档和编码中证明了这种理解(“这一系统已经完成了90%的代码,我们下周就完工了”)
19、,我们必须做好从零开始的心理准备。这一点对于我们定义的用于开发软件系统的活动集合及其交互有重要含义。大脑桶式理论相当于软件开发的线性瀑布模型,其中工程方法的每一步都是被有序地完成的。有一些软件过程,通过避免瀑布模型所固有的线性依存性来处理这一问题。基于风险的开发,将试图通过找出高风险构件来预测一个项目后期的意外。基于问题的开发,将试图完全摆脱线性特征。任何一种开发活动分析、系统设计、对象设计、实现、测试或交付都可能影响其他活动。在基于问题的开发中,所有这些活动都是被并行执行的。非线性开发模型的困难则是难于管理。1.2.4 基本原理在描述知识获取或者知识的进化时,我们准备的知识还不足以描写一个现
20、存系统。一个数学家是如何得到一个证明的?数学课本满是证明,但是很少提供证明导出这一证明过程的线索。因为数学家认为这一背景知识不重要。一旦那些公式和推理规则被给出,其证明就是长期有效的。对软件工程师来说,情况是不同的。开发者对系统的认识是不断变化的。尽管一旦开发者对问题有了足够的理解,应用域模型最终会确定下来,但解决方案域模型将处于不断变化中。在测试阶段发现的设计和实现错误,以及在用户评估阶段发现的可用性问题,都会引起解决方案域模型的变化。新技术也可能引起变化。例如,长效电池和宽带无线通信的出现可能引发移动终端概念的修改。新技术引起的变化通常会产生新的功能性或非功能性的需求。软件工程师通常的任务
21、是修改一个当前可操作的软件系统来吸纳这种新技术。要修改一个系统,理解其当前构件和行为是不够的,还必须捕捉和理解做出每个设计决定的背景。这种额外的知识被称做系统的基本原理。捕捉并深入到一个系统的基本原理不是小事情。首先,每做出一个决定,其他许多备选方案可能已经经过考虑、评估、探讨了。因此,基本原理比解决方案模型反映了更多的信息。其次,基本原理信息通常是隐含的。开发者会基于自己的经验和直觉做出许多决定,而不会对不同方案做出明确的评价。当被要求对某个决定做出解释时,开发者也许要花大量的时间重新研究其基本原理。然而,为了处理经常变化的系统,软件工程师必须面对捕捉基本原理并深入探索基本原理的挑战。1.3
22、 软件工程概念图1-1 用一个UML类图描述的软件工程概念OMG,2001迄今为止,我们已经从建模、问题求解、知识获取和基本原理等方面提出了一种软件工程的高层次视点。在本节中,我们将介绍全书使用的主要术语和概念。1 我们将尽量依据IEEE的软件工程IEEE,1997标准进行定义。一个项目(Project)由许多活动(Activity)组成,其目的在于开发一个软件系统。每种活动则由许多任务(Task)构成。一个任务使用资源(Resource)并产生工作产品(WorkProduct)。一个工作产品可以是一个系统、一个模型或者一个文档。资源包括参与者、时间和设备。这些概念可以用图1-1表示。每一个矩
23、形表示一个概念。矩形间的线段表示概念间的不同关系。例如,菱形表示聚集:一个项目包括许多活动,一个活动又包括许多任务。三角形表示一种归纳关系:参与者(Participant)、时间(Time)和设备(Equipment)都是某种资源。图1-1是用统一建模语言(UML)记号表达的。我们全书都用UML来表达软件模型和其他系统。凭直觉,人们不需要完全理解UML语义就可以理解这个图。同样,使用UML图形表,哪怕用户对UML一无所知,你也可以使用UML图示与客户和用户进行沟通。我们在第2章将详细描述这些图表的语义。1.3.1 参与者和角色开发一个软件系统需要很多来自不同背景、具有不同兴趣的人的协作。例如,
24、开发客户预定和付费系统。现在开发者要构建该系统。项目经理做项目计划和项目预算,并协调开发者和客户。终端用户得到系统的支持。我们把所有参与到这个项目中的人员称为参与者。把项目或系统的一组职责称为角色。一个角色与一组任务联系在一起,且被派给一个参与者。一个参与者能充当多个角色。现在请看一个售票系统(TicketDistributor):售票系统(TicketDistributor)是一台发售火车票的机器。旅客可以选择单程车票和多程车票,也可以选择一天或一周的时间卡。售票系统(TicketDistributor)根据如下信息计算出旅客所要的车票价格:旅行者的地点、旅行者是成人还是儿童。售票系统(Ti
25、cketDistributor)必须能够处理一些意外情况,例如该系统可以处理旅客没有完成交易的情况,可以处理旅客试图使用巨额支票支付的情况,以及可以处理资源用尽的情况:如售完了车票、没有零钱或停电等。把这个售票系统(TicketDistributor)的开发当成一个软件工程项目实施时,表1-1给出了该实例中角色的一些例子。表1-1 售票系统(TicketDistributor)项目软件工程的角色实例角色职责例子客户客户负责提供对系统的高层需求并负责定义项目的范畴(交付日期、预算、质量标准)把售票系统(TicketDistributor)承包出去的列车公司用户用户负责提供有关当前用户任务的域知识
26、;注意客户和用户通常是不同的人旅客经理经理负责工作组织,包括雇佣员工、给他们分派任务、管理工作进程、提供人员培训、总体管理客户提供的资源,直至成功交付Alice(上司)人力专家人力专家负责系统的可用性Zoe(人机交互专家)开发者开发者负责系统的构造,包括:规模说明、设计、实现和测试;在大型项目中,开发者的角色还要被细分John(分析员)、Marc(程序员)、Zoe(测试员)a技术撰写者技术撰写者负责交付客户的文件,技术撰写者要采访开发者、经理和用户,以理解系统Johna开发售票系统(TicketDistributor)是一个小项目,Zoe承担了人力专家和测试员两个角色,John承担了分析员和技
27、术撰写者两个角色。1.3.2 系统和模型我们用系统一词来指内部关联部分的集合。建模是一种通过忽略不相关的细节来处理复杂性的方法。我们用建模一词来指系统的任何抽象。一个地铁售票系统就是一个系统。售票系统的蓝图、电线布线的示意图、软件的对象模型都是售票系统(TicketDistributor)的模型。注意,一个开发项目本身就是一个可建模的系统。其项目规划、预算以及预计的交付期都是开发项目的模型。1.3.3 工作产品一个是一件在开发中生产的人工产品,如给其他开发者或客户开发的一个文档或者一个软件。我们把供项目内部使用的工作产品称为内部工作产品,把必须交付给客户的工作产品称为交付的工作产品。交付的工作
28、产品通常在项目开始之前就已定义,通过与客户签订具有约束的合同,并对开发者加以限定。表1-2描述了一售票系统例子中的一些工作产品实例。表1-2 售票系统项目中一些工作产品的实例工作产品类型描述规格说明交付产品规格说明从用户的角度描述系统,它是项目和客户间的一种契约性文档,售票系统规格说明详细描述了在旅客眼中该系统应该是什么样子操作手册交付产品操作手册是供列车公司负责安装和配置售票系统的工作人员使用的;这种手册描述了诸如如何变化票价,如何将网络结构分成区域等问题状态报告内部工作产品状态报告描述一定时间内已经完成,以及仍在进展中的任务;状态报告是为经理Alice准备的,列车公司通常是看不到的测试手册
29、内部工作产品测试者Zoe负责制作测试计划和测试结果,这些文档跟踪售票系统原型中已知的缺陷及其修改状态,这些文档通常不会给 客户1.3.4 活动、任务和资源活动是为完成某一特定目的的任务集合。例如,需求获取就是一种活动,其目的是与客户一起定义系统将做什么;交付是一种活动,其目的是在一个操作场所安装系统;管理是一种活动,其目的是管理和控制项目,以使其达到目标(即交付期限、质量、预算)。某些活动可由其他一些活动组成。交付活动包括软件安装活动和操作员培训活动。活动有时也被称为阶段。任务代表一种可管理的极小单位的工作:一个经理把它布置给一个开发者,开发者把它实现,经理管理进度以及任务的完成。任务耗费资源
30、,产生工作产品并依赖其他任务生产的工作产品。资源是用来实现工作的资本。资源包括时间、设备和劳动。在规划一个项目时,经理把工作分成任务并把这些任务赋给资源。表1-3描述了软件工程中活动、任务和资源的实例。表1-3 售票系统项目的活动、任务和资源的实例实例类型描述需求获取活动需求获取活动包括从客户和用户那里获得和验证需求和应用域知识;需求获取活动的结果是规格说明工作产品(如表1-2所示)为售票系统开发“没有零钱”的测试用例任务布置给测试员Zoe的这一任务主要是验证售票系统在用完零钱以及找不开用户钱的情况下的行为;这一活动包括规定测试环境、要键入的输入顺序,以及预期的结果检查“获取在线帮助”的使用实
31、例的可用性任务这一布置给人力专家John的任务重点是找出获取系统在线帮助的可用性问题价目表数据库资源价目表数据库包括有一个列车网络计划的价目表结构实例;这一实例是客户提供的一种需求和测试资源1.3.5 功能性需求和非功能性需求需求规定了一个系统必须具有的一组特征。功能性需求是系统必须支持的一种功能的规格说明,非功能性需求是对系统操作的一种约束,与系统的功能无直接关系。例如,用户必须能够买到票以及用户必须能够查到价目信息等属于功能性需求。而用户必须在1秒钟内得到反馈和用于接口的颜色应与公司的颜色一致等属于非功能性需求。其他的非功能性需求可能包括使用某种系统的硬件平台、安全要求、系统应如何应对失误
32、和故障,以及如何提供向后的、与用户不愿弃用的旧系统的兼容性。1.3.6 符号、方法和方法学符号是一种表示一个模型规则的图片或文本集合。罗马字母表是一种表示单词的符号。UML(统一建模语言OMG,2001),即我们在全书中将使用的符号,是一种表示面向对象模型的符号。为了表示面向对象的概念,在软件工程中相当普遍地使用了符号。数据流图De Marco,1978就是一种用数据源、数据汇和数据转换表示系统的一种符号。ZSpivey, 1989是一种表示基于集合理论的系统符号。方法是一种可以重复的技巧,它说明了解决某个具体问题所用的步骤。一种烹饪法是做某道菜的方法。分类算法是一种把一个清单成分进行排序的方
33、法。基本原理管理是一种论证变化的方法。配置管理是一种跟踪变化的方法。方法学是解决一类问题的方法集合,它规定每种方法何时、以何种方式使用。一本收集了烹饪法的海产品烹饪书,如果也包括对配料如何使用,以及如果配料不全该怎么办的建议,就是一种海产品制作方法学。Royce方法学Royce,1998、对象建模技术(OMT Rumbaugh et al.,1991)、Booch方法学Booch,1994以及接触反应Dsouza & Wills,1999都是开发软件的面向对象方法学。软件开发方法学把过程分解为活动。OMT是一种提供3种活动的方法:分析,主要是把系统需求构造成为对象模型;系统设计,主要是些策略性的决定;对象设计,它将分析模型转化成可实现的对象模型。OMT方法学假设需求已经被定义,它不提供获取需求的方法。统一软件开发过程包括分析活动并把系统设计和对象设计当成一种设计活动。统一过程与OMT不同,它包括一种需求获取活动,以用来获取需求以及对需求建模。接触反应
©2010-2025 宁波自信网络信息技术有限公司 版权所有
客服电话:4008-655-100 投诉/维权电话:4009-655-100