参考教材:《软件工程——原理、方法与应用》(第3版)
软件危机指在计算机软件的开发和维护过程中所遇到的一系列严重问题。
软件工程方法的产生源于软件危机,软件的复杂性是产生软件危机的内在原因。
产生软件危机的原因:
Q:什么是软件危机?为什么会产生软件危机?
A:软件危机是指落后的软件生产方式无法满足迅速增长的软件需求,从而导致软件开发与维护过程中出现一系列问题现象。原因主要有:一,软件维护费用急剧上升,直接威胁计算机应用的扩大;二,软件生产技术进步缓慢。
软件的发展,大体上经历了程序、软件和软件产品 3 个阶段。
由上可见,编程范型的演变是伴随着编程粒度的扩大而推进的,这也标志着软件开发技术的不断成熟。
Q:什么是软件生产工程化?工程化生产方法与早期的程序设计方法主要差别在哪里?
A:结构化程序设计的出现,使许多产业界认识到必须把软件生产从个人化方式改变为工程化。采用工程的概念、原理、技术和方法开发与维护软件,把经过时间考验而证明正确的管理技术和当前能够得到最好的技术方法结合起来,以经济地开发出高质量的软件并有效地维护它,这就是软件工程,同时这也是工程化生产方法。
Q:什么是软件生存周期?把生存周期划分为阶段的目的是什么?
A:软件生存周期划分为计划、开发和运行三个时期;把整个生存周期划分为较小的阶段,给每个阶段赋予确定而有限的任务,就能够化简每一步工作内容,使因软件规模而增长而大大增加了软件复杂性得交易控制和管理。
软件生存周期的主要活动:
需求分析 → 软件分析 → 软件设计 → 编码(测试)→ 软件测试 → 运行维护
瀑布开发模型是一种基于软件生存周期的线性开发模型。
瀑布模型的缺点是缺乏灵活性,特别是无法解决软件需求不明确或不准确的问题。
由于用户不可能一次性的提出所有的需求,而瀑布模型是属于“线性”的开发模型,因而瀑布模型不能适应用户在开发后期提出的需求变更。
按照瀑布模型来开发软件,只有当分析员能够做出准确的需求分析时,才能够得到预期的结果。不幸的是,由于多数用户不熟悉计算机,系统分析员对用户的专业也往往了解不深,因而很难在开发的初始阶段彻底弄清软件需求。为了解决这一问题,人们提出了“快速原型模型”。
原型化方法是用户和设计者之间执行的一种交互构成,适用于需求不确定性高的情况。
在快速原型模型的开发过程中,用原型过程来代替全部开发阶段所用模型是演化型原型模型。
软件开发人员向用户提供一个“样品”,用户向开发人员迅速作出反馈。
下图显示了快速原型软件开发的过程模型。
用户的介入和反馈,使它在原型的分析与设计阶段可能出现多次回溯和迭代,从而形成非线性的开发模型。
常见的演化模型有增量模型与螺旋模型两种。它们都是瀑布模型和快速原型模型相结合的产物。
适用于大型软件的开发。
项目按照顺时针方向沿螺旋线移动时,每轮螺旋包含以下四种活动:
按此顺序周而复始,直到实现最终产品。
螺旋模型的特点,是在项目的所有阶段都考虑各类风险,从而能在风险变成问题之前降低它的危害。螺旋模型开发的成败,在很大程度上依赖于风险评估的准确性。
适用于面向对象的软件开发。
统一建模语言(unified modeling language,UML),把众多面向对象分析和设计工具综合成一种标准,使面向对象的方法成为主流的软件开发方法。
面向对象思想最重要的特征是在解空间中引入了“对象”的概念。
面向对象方法学包含了对象(object)、类(class)、继承(inheritance)、消息(message)等核心概念。
面向对象 = 对象 + 分类(classification)+ 继承 + 消息通信(communication with messages)
软件开发方法可分为:
转换模型是将形式化软件开发和程序自动生成技术相结合的一种软件开发模型。
净室模型是一种形式化的增量开发模型。
基本思想:力求在分析和设计阶段就消除错误,确保正确,然后在无缺陷或“洁净”的状态下实现软件的制作。
Q:RUP是什么? 试比较RUP和XP的差异。
A:RUP(Rational Unified Process,统一软件开发过程,统一软件过程)是一个面向对象且基于网络的程序开发方法论。
RUP统一软件过程是描述软件开发中各个环节应该做什么,怎么做,什么时候做以及为什么要做,描述了以某种顺序完成的活动。其在一个二维空间中描述软件开发活动,可以分为初始阶段,细化阶段,构造阶段和迁移阶段。
XP 极限过程是一个轻量级的,敏捷的软件开发方法,同时也是一个非常严谨和周密的方法。它有四个价值观:交流,简单,反馈和勇气。
统一过程描述了软件开发中各个环节做的内容:
统一过程包括四个阶段:
敏捷开发(agile development)是一种以人为核心、以迭代方式循序渐进开发的方法,其软件开发的过程称为“敏捷过程”。
下图为 4 个简单的价值观以及敏捷开发方法应遵循的 12 条原则:
极限编程是敏捷过程的一种方法。
它有 4 个价值观:
即,任何一个软件项目都可以从 4 个方面入手进行改善:
可行性论证其实是在高层次上进行的一次大大简化了的需求分析与设计。
可行性研究进一步研究问题分析阶段所确定的问题是否有可行的解。
第一代(传统软件工程)→ 第二代(OO软件工程)→ 第三代(基于构件的软件工程)
本章重点介绍基于瀑布模型的结构化分析与设计。
系统的整个开发流程,可以简明地表示为:
任务:
步骤:
数据流图和数据字典共同构成了系统的逻辑模型,是需求规格说明书的主要组成部分。
SD 阶段先把分析模型中的 DFD 图转换为最终 SC 图。
软件设计 = 概要/总体设计 + 详细设计/模块设计
前者以 SD 方法为代表,后者以 Jackson 方法为代表。
由图可见,数据字典(DD)处于模型的核心,它是系统涉及的各种数据对象的总和。从DD出发可构建 3 种图:
高度抽象的软件系统功能模型:
数据流图只使用 4 种基本图形符号:
判定表或判定树
某公司为推销人员制定了奖励办法,把奖金与推销金额及预收贷款的数额挂钩。凡每周推销金额不超过 10000 元的,按预收贷款是否超过 50%,分别奖励推销额的 6% 或 4%。若推销金额超过 10000 元,则按预收贷款是否超过 50% ,分别奖励推销额的 8% 或 5%。对于月薪低于 1000 元的推销员,分别另发鼓励奖 300、200 和 500、300 元。试分别采用判定表和判定树为 DFD 图中用来“计算奖金”的加工写出 PSPEC。
下图分别显示了用判定表和判定树描述的 PSPEC,二者的含义相同。
其描述工具为结构图(structure chart),简称 SC 图。
软件结构图中,模块框之间若有直线连接,表示它们之间存在调用关系。
由传入路径、变换中心和传出路径 3 部分组成。
事务型结构由至少一条接受路径、一个事务中心与若干条动作路径组成。
一般来说,模块的总行数应该控制在 10-100 行的范围内,最好为 30-60 行,能容纳在一张打印纸内。
扇入高则上级模块多,能够增加模块的利用率;扇出低则表示下级模块少,可以减少模块调用和控制的复杂度。
设计良好的软件通常具有瓮型(oval-shaped)结构,两头小,中间大,如图所示。这类软件在下部收拢,表明它在低层模块中使用了较多高扇入的共享模块。
目的:为 SC 图中的每个模块确定采用的算法和块内数据结构,用选定的表达工具给出清晰的描述。
任务:编写软件的模块设计说明书。
UML 是一种基于面向对象的可视化建模语言。
以下是几种主要连接关系的含义:
Q:请指出 UML 类图中类之间的除聚合与组合之外的关系有哪些?聚合与组合关系有什么区别和联系?
A:还有的关系有:关联、依赖、继承、实现。聚合与组合的区别是:聚合表示两个对象之间是整体和部分的弱关系,部分的生命周期可以超越整体;组合表示两个对象之间是整体和部分的强关系,部分的生命周期不能超越整体,或者说不能脱离整体而存在。聚合是一种特殊的关联,而组合又是一种特殊的聚合。
模型定义了用于描述信息领域的语言,它组成了 UML 的基本元素。
UML的静态建模机制包括:
根据指定的条件,一个用例中有可能加入另一个用例的动作,这两个用例之间的关系就是扩展关系。
当一个用例的行为包含另一个用例的行为时,这两个用例之间就构成了包含关系。如果若干个用例有某些行为是相同的,即可把这些相同的行为抽取出来单独成为一个用例,称为抽象用例。
类图是最重要的模型图,它描述了系统中各类对象以及它们之间的各种关系。
不同的属性具有不同的可见性。常见的可见性和在 UML 中的表示:
类图可描述类与类之间的静态关系:
在 OO 设计中,可将许多类集合成一个更高层次的单位,形成一个高内聚、低耦合的类的集合。
UML 把这种将一些模型元素组织成语义上相关的组的分组机制称为包。
UML 定义的消息类型有以下 3 种:
状态图(state diagram)用来描述一个特定对象的所有可能状态以及引起其状态转移的事件。
交互图有顺序图和协作图两种形式。
时序图(sequence diagram)用来描述对象之间的动态交互,着重体现对象间消息传递的时间顺序。
协作图(collaboration diagram)用于描述相互协作的对象间的交互和链接。
活动图(activity diagram)显示动作流程及其结果,它既可用来描述操作(类的方法)的行为,也可以描述用例和对象内部的工作过程。
需求分析阶段最重要的的技术文档之一是需求规格说明书(SRS)。
在需求分析中,分析员要从用户那里解决的最重要的问题是明确软件做什么。
软件需求主要指一个软件系统必须遵循的条件或具备的能力。
这里的条件或能力可以从两个方面来理解:
软件需求一般包括 3 个不同的层次:
需求分析的目的主要是为待开发的软件系统进行需求定义与分析,并建立一个需求模型(requirement model)。
软件的需求分析一般包括如下的 4 个步骤:
第四代开发技术(4GT)是快速原型法的常用技术。
步骤:
用例规约文档一般包含以下内容:
SRS包括:
变更申请 → 审批 → 更改 → 重新确认
对软件影响大的需求变更,应该提交给SCCB(软件变更控制委员会)审批。
Q:需求分析的任务是什么?怎样理解分析阶段的任务是决定“做什么”,而不是“怎么做”?
答:需求分析主要有两个任务:
1)通过对问题及其环境的理解、分析和综合建立分析模型;
2)是在完全弄清用户对软件系统的确切要求的基础上,用“软件需求规格说明书”把用户的需求表达出来。需求分析的任务就是为了明确要开发的是一个什么系统,而不是怎么去实现这个系统。
UML 是面向对象分析(object-oriented analysis,OOA)的重要表达工具。
首先要理解用户的需求,包括全面理解和分析用户需求,明确所开发的软件系统的职责,形成文件并规范地加以表述。然后进行分析,提取类和对象,并结合分析进行建模。
如图所示,处于 OOA 模型核心的是以用例模型为主体的需求模型。当软件开发小组获得软件需求后,分析员即可据此创建一组场景(scenario)。
与传统的软件分析方法相比较,面向对象分析具有如下优点:
分析模型由一组子模型组成。
特点:
通常,分析类被划分为 3 种类型:
可分别用标记
来表示。
在面向对象设计阶段着重完成“如何做”的问题,也就是着重考虑对象的实现细节。
在面向对象的设计中,我们应遵循的设计准则除了模块化、抽象、低耦合、高内聚以外,还有信息隐蔽。
系统分解为模块时应遵循的指导思想。
这一指导思想的目的,是为了提高模块的独立性。
独立性可以从两个方面来度量:
模块的独立性愈高,则块内联系越强,块间联系越弱。
C.Myers 把内聚和耦合各划分为 7 类,现分别介绍如下。
内聚是从功能的角度对模块内部聚合能力的量度。
最强:功能性内聚
最弱:偶然性内聚
耦合是对软件内部块间联系的度量。
最强:内容耦合
最弱:非直接耦合
Q:衡量模块独立性的两个定性标准是什么?这两个标准的定义分别是什么?在我们的软件设计中,关于模块独立性我们追求的目标是什么?
A:衡量模块独立性的两个定性标准是内聚和耦合。耦合是指对一个软件结构内不同模块彼此之间互相依赖(连接)的紧密程度;而内聚则标志一个模块内部各个元素彼此结合的紧密程度。在我们的软件设计中,关于模块独立性我们追求的目标是紧密内聚松散耦合(或者高内聚低耦合)。
OO 设计模型由
4 个层次组成。
正如传统设计可分为概要设计和详细设计两个阶段,OOD 的软件设计也可划分为两个层次:
设计任务:将分析阶段建立的分析模型转变为软件设计模型。
设计目标:细化解决方案的可视化设计模型,确保设计模型最终能平滑地过渡到程序代码。
软件系统架构是指系统主要组成元素的组织或结构,以及其他全局性决策,组成元素之间通过接口进行交互。
系统元素包括组成系统的类、子系统与接口、包等。系统元素设计是对每一个设计元素进行详细的设计。
每个模式都描述了一个在某个特定环境中不断出现的问题,然后描述该问题解决方案的核心。就其抽象的级别而言,软件模式可以分为:
E.W.Dijkstra 有一句名言:“程序测试只能证明错误的存在,不能证明错误不存在。”
黑盒测试就是根据被测试程序功能来进行测试,所以也称为功能测试。
边界值分析方法是取输入/输出等价类的边界值来构成测试用例的测试方法。
白盒测试以程序的结构为依据,所以又称为结构测试。
白盒测试仅与程序的内部结构有关,完全可以不考虑程序的功能要求。
Q:简述软件测试的目的、任务与动态测试类型。
A:软件测试是一个为了寻找软件错误而运行程序的过程。目的就是为了发现软件中的错误。软件测试的任务是通过在计算机上执行程序,暴露程序中的潜在的错误。(一个好的测试用例是指很可能找到迄今为止尚未发现的错误的用例。一个成功的测试是指揭示了迄今为止尚未发现的错误的测试。)动态软件测试主要分为白盒测试和黑盒测试两大类。
按照软件工程的观点,多模块程序的测试共包括 4 个层次。
在进行软件测试时,首先应当进行单元测试,然后再进行组装测试,最后再进行有效性测试。
通过对象模块的静态分析与动态测试,使其代码达到模块说明书的需求。
单元测试阶段主要涉及详细设计的文档。
将经过单元测试的模块逐步组装成具有良好一致性的完整的程序。
确认组装完毕的程序是否满足软件需求规格说明书(SRS)的要求。
针对软件需求分析所进行的软件测试是指确认测试。
检查把确认测试合格的软件安装到系统中以后,能否与系统的其余部分协调运行,并且实现 SRS 的要求。
单元测试是发现编码错误,集成测试是发现模块的接口错误,确认测试是为了发现功能错误,那么系统测试是为了发现性能、质量不合要求的错误。
产生软件维护的副作用是指因修改软件造成的错误。
软件生命周期中所花费用最多的阶段是软件维护。
软件过程的输出信息可以分为 3 个主要类别:其一是计算机程序(源代码和可执行程序),其二是描述计算机程序的文档(针对技术开发者和用户),其三是数据(包含在程序内部或外部)。这些项包含了所有在软件过程种产生的信息,总称为软件配置项。
回归测试是指重新执行已经做过的测试的某个子集,以保证由于调试或其他原因引起的变化,不会导致非预期的软件行为或额外错误的测试活动。
针对下面一个程序段
if ((A > 1) && (B == 0)) {
X = X / A;
}
if ((A == 2) || (X > 1)) {
X++;
}
选取测试用例:CASE 1:A=2 B=0 X=3,该测试用例满足了语句覆盖。
软件是程序及其文档。
文档是软件产品的一部分,没有文档的软件就不称其为软件。
软件工程的三要素是工具、过程和方法。
系统边界是一个系统所包含的所有系统成分与系统以外各种事物的分界线。
在用例之间,会有三种不同的关系:
一台计算机有很多零部件,例如:键盘、鼠标、主板、显示器等等,我们可以用一个聚集图来描述,也就是说计算机是一个聚集体。
数据管理部分的设计是 OOD 模型中的一部分,负责使用关系数据库存储和检索永久对象。(×)
一个软件从开始立项起,到废止不用止,统称为软件的生命周期。
软件生存周期主要活动:
从心理学角度看,对数据流程图的数据处理泡进行分解,一次分解为7±2个泡为宜。
结构化程序设计采用的三种基本控制结构:
结构化程序设计主要强调的是程序易读性。
解释下列名词:(1)模块;(2)模块化;(3)模块化设计。
答:模块是一个拥有明确定义的 、输出和特性的程序实体。
模块化是指解决一个复杂问题时自顶向下逐层把软件系统划分成若干模块的过程。每个模块完成一个特定的子功能,所有的模块按某种方法组装起来,成为一个整体,完成整个系统所要求的功能。
模块化设计是把大型软件按照规定的原则划分成一个个较小的、相对独立但又相互关联的模块。但又相互关联的模块。