第1章 软件工程学概述
1.1 软件危机
1.1.1 软件危机的介绍
软件危机(软件萧条、软件困扰):是指在计算机软件的开发和维护过程中所遇到的一系列严重问题。
软件危机包含下述两方面的问题:
如何开发软件,满足对软件日益增长的需求;
如何维护数量不断膨胀的已有软件。
软件危机的典型表现:
(1)对软件开发成本和进度的估计常常很不准确;
(2)用户对“已完成的”软件系统不满意的现象经常发生;
(3)软件产品的质量往往靠不住;
(4)软件常常是不可维护的;
(5)软件通常没有适当的文档资料;
(6)软件成本在计算机系统总成本中所占的比例逐年上升;
(7)软件开发生产率提高的速度,远远跟不上计算机应用迅速普及深入的趋势 。
1.1.2 产生软件危机的原因
(1)与软件本身的特点有关
(2)与软件开发与维护的方法不正确有关
1.1.3 消除软件危机的途径
对计算机软件有正确的认识。
认识到软件开发是一种组织良好、管理严密、各类人员协同配合、共同完成的工程项目。
应该推广使用在实践中总结出来的开发软件的成功技术和方法,并继续研究探索。
应该开发和使用更好的软件工具。
总之,为了解决软件危机,既要有技术措施(方法和工具),又要有必要的组织管理措施。
1.2 软件工程
1.2.1 软件工程的介绍
软件工程:是指导计算机软件开发和维护的一门工程学科。采用工程的概念、原理、技术和方法来开发与维护软件,把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来,以经济地开发出高质量的软件并有效地维护它,这就是软件工程。
软件工程的本质特性:
- 软件工程关注于大型程序的构造
- 软件工程的中心课题是控制复杂性
- 软件经常变化
- 开发软件的效率非常重要
- 和谐地合作是开发软件的关键
- 软件必须有效地支持它的用户
- 在软件工程领域中是由具有一种文化背景的人替具有另一种文化背景的人创造产品
1.2.2 软件工程的基本原理 - 用分阶段的生命周期计划严格管理
- 坚持进行阶段评审
- 实行严格的产品控制
- 采用现代程序设计技术
- 结果应能清楚地审查
- 开发小组的人员应该少而精
- 承认不断改进软件工程实践的必要性
1.2.3 软件工程方法学
软件工程包括技术和管理两方面的内容。
软件工程方法学3要素:方法、工具、过程
软件工程方法学常见类型:
- 传统方法学(生命周期方法学或结构化范型)——强调自顶向下
- 面向对象方法学——强调主动地多次反复迭代,面向对象方法学4个要点:对象、类、继承、消息
1.3 软件生命周期
三个时期八个阶段:软件生命周期由软件定义、软件开发和运行维护(也称为软件维护)三个时期组成,每个时期又进一步划分成若干个阶段。
1.4 软件过程
1.4.1 瀑布模型
- 定义
瀑布模型是将软件生存周期的各项活动规定为按固定顺序而连接的若干阶段工作,形如瀑布流水,最终得到软件产品。
可行性研究的实质: 进行一次大大压缩简化了的系统分析和设计的过程,也就是在较高层次上以较抽象的方式进行的系统分析和设计的过程。
可行性研究的内容: 首先进一步分析和澄清问题定义,导出系统的逻辑模型; 然后从系统逻辑模型出发,探索若干种可供选择的主要解法(即系统实现方案); 对每种解法都研究它的可行性,至少应该从三方面研究每种解法的可行性 。
主要方面: 技术可行性,经济可行性,操作可行性,
其他方面: 运行可行性, 法律可行性,
2.2 可行性研究过程
- 复查系统规模和目标
- 研究目前正在使用的系统
- 导出新系统的高层逻辑模型 4. 进一步定义问题 5. 导出和评价供选择的解法 6. 推荐行动方针 7. 草拟开发计划 8. 书写文档提交审查 2.3 系统流程图
系统流程图:是概括地描绘物理系统的传统工具。表达的是数据在系统各部件之间流动的情况,而不是对数据进行加工处理的控制过程。
2.4 数据流图(必考,非常重要)
2.4.1 符
基本符 :
数据存储:数据存储是处于静止状态的数据; 数据流:数据流是处于运动中的数据。
附加符 : 星 (*):表示“与”关系
加 (+):表示“或”关系 异或(⊕):表示互斥关系
2.5 数据字典(必考,非常重要)
数据流图和数据字典共同构成系统的逻辑模型。
数据字典是关于数据的信息的集合,也就是对数据流图中包含的所有元素的定义的集合,是所有与系统相关的数据元素的有组织的列表,并且包含了对这些数据元素的精确、严格的定义,从而使得用户和系统分析员双方对输入、输出、存储的成分甚至中间计算结果有共同的理解。简而言之,数据字典是描述数据的信息的集合,是对系统中使用的所有数据元素的定义的集合。是为了描述在结构化分析过程中定义对象的内容时,使用的一种半形式化的工具。
2.5.1 数据字典的内容 数据字典的组成:数据流 数据流分量(即数据元素) 数据存储 处理
2.5.2 定义数据的方法
方法:对数据自顶向下分解。 数据组成方式(三种基本类型):顺序 选择 重复 附加类型:可选
符 : =意思是等价于(或定义为); +意思是和(即,连接两个分量); [ ]意思是或(即,从方括弧内列出的若干个分量中选择一个),通常用“|” 隔开供选择的分量; { }意思是重复(即,重复花括弧内的分量);常常使用上限和下限进一步注释表示重复的花括弧。 ( )意思是可选(即,圆括弧里的分量可有可无)。
2.5.3 数据字典的实现
计算机实现 人工实现
2.6 成本/效益分析
2.6.1 成本估计:
- 代码行技术
- 任务分解技术
- 自动估计成本技术
2.6.2 成本/效益分析的方法
成本/效益分析涉及的4个概念: 1. 货币的时间价值 2. 投资回收期 3. 纯收入 4. 投资回收率:P = F1/( 1 + j ) + F2/( 1 + j )2 + …+ Fn( 1 + j )n
第3章 需求分析
需求分析的任务: 需求分析是软件定义时期的最后一个阶段,它的基本任务是准确地回答“系统必须做什么这个问题。 确定系统必须完成哪些工作,也就是对目标系统提出完整、准确、清晰、具体的要求。 系统分析员应该写出软件需求规格说明书,以书面形式准确地描述软件需求
3.1 需求分析的任务
确定对系统的综合要求 分析系统的数据要求 导出系统的逻辑模型 修正系统开发计划
3.1.1 确定对系统的综合要求
- 功能需求
- 性能需求 3. 可靠性和可用性需求 4. 出错处理需求 5. 接口需求 6. 约束 7. 逆向需求 8. 将来可能提出的要求
3.1.2 分析系统的数据要求
建立数据模型——ER图 描绘数据结构——层次方框图和Warnier图 数据结构规范化
3.2 与用户沟通获取需求的方法
访谈类型: - 正式访谈
- 非正式访谈
- 调查表
- 情景分析技术
问题:面向数据流为什么采用自顶向下求精的方法br> 答:“自顶向下, 逐步求精”的程序设计方法是结构化程序设计,是面向数据流进行需求分析的方法。采用自顶向下、逐步求精,建立系统的处理流程,以数据流图和数据字典为主要工具,建立系统的逻辑模型。
“自顶向下” 是将复杂、大的任务按功能进行分解划分为小问题,找出问题的关键、重点所在,然后用精确的思维定性、定量地去描述问题。
“逐步求精” 是将现实世界的问题经抽象转化为逻辑空间或求解空间的问题。复杂问题经抽象化处理变为相对比较简单的问题。经若干步抽象(精化)处理,最后到求解域中只是比较简单的编程问题,再细分就是用函数来解决问题。
问题:简易的应用规格说明技术的流程
答:通常,首先进行初步的访谈,通过用户对基本问题的回答,对待解决的问题的范围和解决方案有了总体认识,然后开发者和用户都写出“产品需求”。选定会议地点、日期和时间,并选举一个协调人。邀请开发者和用户双方组织的代表出席会议,在会议日期之前把写好的产品需求分发给每位与会者。
要求每位与会者在开会的前几天认真复审产品需求,并且列出作为系统环境组成部分的对象、系统将产生的对象以及系统为了完成自己的功能将使用的对象。此外,还要求每位与会者列出操作这些对象或与这些对象交互的服务(即处理或功能)。最后,还应该列出约束条件(例如成本、规模、完成日期)和性能标准 (例如速度、精度)。并不期望每位与会者列出的内容都是毫无遗漏的,但是,希望能准确表达出每个人对目标系统的认识。
会议开始之后,讨论的第一个议题是是否需要这个新产品,一旦大家都同意确实需要这个新产品,每位与会者就应该展示他们在会前准备好的列表供大家讨论。可以把这些列表抄写在大纸上钉在墙上,或者写在白板上挂在墙上。理想的情况是,表中每一项都能单独移动,这样就能删除或增添表项,或组合不同的列表。在这个阶段,严格禁止批评与争论。
在展示了每个人针对某个议题的列表之后,小组共同创建一张组合列表。在组合列表中消去了冗余项,加入了在展示过程中产生的新想法,但是并不删除任何实质性内容。在针对每个议题的组合列表都建立起来之后,由协调人主持讨论。组合列表将被缩短、加长或重新措辞,以便更恰当地描述将被开发的产品。讨论的目标是,针对每个议题(对象、服务、约束和性能)都创建出一张意见一致的列表。
一旦得出了意见一致的列表,就把与会者分成更小的小组,每个小组的工作目标是为每张列表中的一个或多个项目制定出小型规格说明。小型规格说明是对列表中包含的单词或短语的准确说明。
然后,每个小组都向全体与会者展示他们制定出的小型规格说明供大家讨论。通过讨论可能会增加或删除一些内容,也可能做一螋进一步的精化工作。在讨论过程中还可能提出一些无法在这次会议中解决的问题,应该保存问题清单,以便这些想法在以后的活动中起作用。
在完成了小型规格说明之后,每个与会者都制定出产品的一整套确认标准,并把自己制定的列表提交会议讨论,以创建出意见…一致的确认标准列表。最后,由一名或多名与会者根据会议成果起草完整的规格说明。
简易的应用规格说明技术并不是解决需求分析阶段遇到的所有问题的“万能灵药”,但是,这种面向团队的需求收集方法确实有许多突出的优点:开发者与用户不分彼此,集思广益,益密切合作;即时讨论和求精;有能导出规格说明的具体步骤。
快速建立软件原型:(1) 第四代技术(4GL)(2) 可重用的软件构件 (3) 形式化规格说明和原型环境
3.3分析建模与规格说明(不考)
3.4 实体-联系图
3.4.1 数据对象:是软件必须理解的符合信息的抽象
3.4.2 属性:定义了数据对象的性质
3.4.3 联系:数据对象彼此之间的相互连接的方式
分为3种类型:
(1) 一对一联系(1:1)
(2) 一对多联系(1:n)
(3) 多对多联系(M:N)
3.4.4 实体-联系图的符 : 矩形框;椭圆框;菱形框
3.5 数据规范化
(1)第一范式 每个属性值都必须是原子值,即仅仅是一个简单值而不含内部结构
(2)第二范式 满足第一范式条件,而且每个非关键字属性都由整个关键字决定(而
不是由关键字的一部分来决定)
(3)第三范式 符合第二范式的条件,每个非关键字属性都仅由关键字决定,而且一
个非关键字属性不能仅仅是对另一个非关键字属性的进一步描述(即一个非关键字属性
值不依赖于另一个非关键字属性值)。
3.6 状态转换图 (考画图)
3.6.1 状态
状态是任何可以被观察到的系统行为模式,一个状态代表系统的一种行为模式,状态规定了系统对事件的响应方式。
状态图分类: 表示系统循环运行过程,通常不关心循环是怎样启动的。 表示系统单程生命期,需要标明初始状态和最终状态。
3.6.2 事件
事件是在某个特定时刻发生的事情,它是对引起系统做动作或(和)从一个状态转换到另一个状态的外界事件的抽象。
3.6.3 符
3.7 其他图形工具
3.7.1 层次方框图(画图)
3.7.2 Warnier图(画图)
3.7.3 IPO图(画图)
3.8 验证软件需求
问题:从哪些方面验证软件需求的正确性
一致性 完整性 现实性 有效性
第4章 形式化说明技术(不考)
第5章 总体设计
5.1 设计过程
由两个主要阶段组成: (1)系统设计阶段,确定系统的具体实现方案:
① 设想供选择的方案
② 选取合理的方案
③ 推荐最佳方案
(2)结构设计阶段,确定软件结构:
④ 功能分解
⑤ 设计软件结构
⑥ 设计数据库
⑦ 制定测试文档
⑧ 书写文档
⑨ 审查和复查
5.2 设计原理
5.2.1 模块化
模块化的作用: 采用模块化原理可以使软件结构清晰,不仅容易设计也容易阅读和理解。 模块化使软件容易测试和调试,因而有助于提高软件的可靠性。 模块化能够提高软件的可修改性。 模块化也有助于软件开发工程的组织管理。
5.2.2 抽象
5.2.3 逐步求精
5.2.4 信息隐藏和局部化
5.2.5 模块独立
尽量使用数据耦合, 少用控制耦合和特征耦合, 限制公共环境耦合的范围,
完全不用内容耦合。
七种内聚的优劣评分结果: 高内聚:功能内聚 顺序内聚 中内聚:通信内聚 过程内聚 低内聚:时间内聚 逻辑内聚 偶然内聚
5.3 启发规则
- 改进软件结构提高模块独立性
- 模块规模应该适中
- 深度、宽度、扇出和扇入都应适当
- 模块的作用域应该在控制域之内
- 力争降低模块接口的复杂程度
- 设计单入口单出口的模块
- 模块功能应该可以预测
5.4 描绘软件结构的图形工具
5.4.1 层次图和HIPO图(画图) - 层次图(H图) 层次图用来描绘软件的层次结构。很适于在自顶向下设计软件的过程中使用。
- HIPO图
5.4.2 结构图
5.5 面向数据流的设计方法
结构化设计方法(简称SD方法),也就是基于数据流的设计方法。
5.5.1 概念
面向数据流的设计方法把信息流映射成软件结构,信息流的类型决定了映射的方法。 信息流有两种类型:变换流 事务流
5.5.2 变换分析
5.5.3 事务分析
5.5.4 设计优化
第6章 详细设计
6.1 结构程序设计
经典的结构程序设计:
只允许使用顺序、IF-THEN-ELSE型分支和DO-WHILE型循环这3种基本控制结构; 扩展的结构程序设计:
除了上述3种基本控制结构之外,还允许使用DO-CASE型多分支结构和DO-UNTIL型循环结构; 修正的结构程序设计:
再加上允许使用LEAVE(或BREAK)结构。
6.2 人机界面设计
6.2.1 设计问题
设计人机界面过程中会遇到的4个问题: 系统响应时间:长度 易变性 用户帮助设施:集成的帮助设施附加的帮助设施 出错信息处理 命令交互 6.2.2 设计过程
6.2.3 人机界面设计指南
一般交互指南 信息显示指南 数据输入指南 6.3过程设计的工具
6.3.1 程序流程图(程序框图)
程序流程图的主要缺点: 程序流程图本质上不是逐步求精的好工具,它诱使程序员过早地考虑程序的控制流程,而不去考虑程序的全局结构。 程序流程图中用箭头代表控制流,因此程序员不受任何约束,可以完全不顾结构程序设计的精神,随意转移控制。 程序流程图不易表示数据结构。
6.3.2 盒图(N-S图)
盒图具有下述特点: 功能域明确。 不可能任意转移控制。 很容易确定局部和全程数据的作用域。 很容易表现嵌套关系,也可以表示模块的层次结构。 6.3.3 PAD图
它用二维树形结构的图来表示程序的控制流,将这种图翻译成程序代码比较容易。
PAD图的主要优点如下: 使用表示结构化控制结构的PAD符 设计出来的程序必然是结构化程序。 PAD图所描绘的程序结构十分清晰。 PAD图表现程序逻辑易读、易懂、易记。 容易将PAD图转换成高级语言源程序,这种转换可用软件工具自动完成。 即可表示程序逻辑,也可描绘数据结构。 PAD图的符 支持自顶向下、逐步求精方法的使用。 6.3.4 判定表
判定表却能够清晰地表示复杂的条件组合与应做的动作之间的对应关系。
所有条件 条件组合矩阵
所有动作 条件组合
对应的动作
判定表的缺点:
判定表的含义不是一眼就能看出来的,初次接触这种工具的人理解它需要有一个简短的学习过程。
当数据元素的值多于两个时,判定表的简洁程度也将下降。
6.3.5 判定树
判定树的优点:
它的形式简单,一眼就可以看出其含义,因此易于掌握和使用。
判定树的缺点:
简洁性不如判定表,数据元素的同一个值往往要重复写多遍,而且越接近树的叶端重复次数越多。
画判定树时分枝的次序可能对最终画出的判定树的简洁程度有较大影响。
6.3.6 过程设计语言(伪码)
伪代码的基本控制结构:
简单陈述句结构:避免复合语句。
判定结构:IF_THEN_ELSE或CASE_OF结构。
选择结构:WHILE_DO或REPEAT_UNTIL结构。
A由B、C、D 3个元素顺序组成 根据条件A是B或C或D中的某一个 A由B出现N次(N≥0)组成
6.4.2 改进的Jackson图
6.4.3 Jackson方法
6.5 程序复杂程度的定量度量
6.5.1 McCabe方法
-
流图(程序图)
-
计算环形复杂度的方法
V(G)=流图中的区域数
V(G)=E-N+2
其中E是流图中的边数,N是结点数
V(G)=P+1
其中P是流图中判定结点的数目
6.5.2 Halstead方法
令N1为程序中运算符出现的总次数,N2为操作数出现的总次数,程序长度N定义为:
N=N1+N2
程序中使用的不同运算符(包括关键字)的个数n1,以及不同操作数(变量和常数)的个数n2。预测程序长度的公式如下:
H = n1 log2n1 + n2 log2n2
预测程序中包含错误的个数的公式如下:
E = N log2 (n1+n2)/3000
第7章 实现
编码和测试统称为实现。
7.1编码
7.1.1 选择程序设计语言
主要的实用标准:
系统用户的要求
可以使用的编译程序
可以得到的软件工具
工程规模
程序员的知识
软件可移植性要求
软件的应用领域
7.1.2 编码风格
- 程序内部的文档:恰当的标识符 适当的注解 程序的视觉组织
- 数据说明
- 语句构造
- 输入输出
- 效率:程序运行时间 存储器效率 输入输出的效率
7.2软件测试基础
7.2.1 软件测试的目标
测试是为了发现程序中的错误而执行程序的过程;
好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案;
成功的测试是发现了至今为止尚未发现的错误的测试。
7.2.3 测试方法
黑盒测试(功能测试):
把程序看作一个黑盒子;
完全不考虑程序的内部结构和处理过程;
是在程序接口进行的测试。
白盒测试(结构测试):
把程序看成装在一个透明的盒子里;
测试者完全知道程序的结构和处理算法;
按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按预定要求正确工作。
7.2.4 测试步骤 - 模块测试(单元测试)
保证每个模块作为一个单元能正确运行;
发现的往往是编码和详细设计的错误。 - 子系统测试
把经过单元测试的模块放在一起形成一个子系统来测试;
着重测试模块的接口。 - 系统测试
把经过测试的子系统装配成一个完整的系统来测试;
发现的往往是软件设计中的错误,也可能发现需求说明中的错误;
不论是子系统测试还是系统测试,都兼有检测和组装两重含义,通常称为集成测试。 - 验收测试(确认测试)
把软件系统作为单一的实体进行测试;
它是在用户积极参与下进行的,而且可能主要使用实际数据(系统将来要处理的信息)进行测试;
发现的往往是系统需求说明书中的错误。 - 平行运行
7.2.5 测试阶段的信息流(了解一下)
输入信息有两类:
软件配置,包括需求说明书、设计说明书和源程序清单等;
测试配置,包括测试计划和测试方案。
7.3 单元测试
单元测试集中检测模块;
单元测试和编码属于软件过程的同一个阶段;
可以应用人工测试和计算机测试这样两种不同类型的测试方法;
单元测试主要使用白盒测试技术,对多个模块的测试可以并行地进行。
7.3.1 测试重点
模块接口
局部数据结构
重要的执行通路
出错处理通路
边界条件
7.3.2 代码审查
由审查小组正式进行测试称为代码审查;
审查小组人员:
- 组长,应该是一个很有能力的程序员,而且没有直接参与这项工程
- 程序的设计者
- 程序的编写者
- 程序的测试者
一次审查会上可以发现许多错误,可以减少系统验证的总工作量。
7.3.3 计算机测试
驱动程序是一个“主程序”,它接收测试数据,传送给被测试的模块,并且印出有关的结果。
存根程序代替被测试的模块所调用的模块。它使用被它代替的模块的接口,可能做最少量的数据操作,印出对入口的检验或操作结果,并且把控制归还给调用它的模块。
7.4 集成测试
集成测试是测试和组装软件的系统化技术,主要目标是发现与接口有关的问题。
由模块组装成程序时有两种方法:
7.4.1 自顶向下集成
优点:
能在早期验证主要的控制和判断点。
选用按深度方向组装的方式,可以首先实现和验证一个完整的软件功能。
缺点:可能遇到逻辑次序上的问题,存根程序编写问题
7.4.2 自底向上集成
优点:对底层组件行为较早验证;工作最初可以并行集成,比自顶向下效率高;减少了桩的工作量;支持故障隔离。
缺点:驱动的开发工作量大;对高层的验证被推迟,设计上的错误不能被及时发现。
适应于底层接口比较稳定;高层接口变化比较频繁;底层组件较早被完成。
7.4.3 不同集成测试策略的比较
混合策略:
改进的自顶向下测试方法
混合法
7.4.4 回归测试
回归测试集(已执行过的测试用例的子集)包括下述3类不同的测试用例
(1)检测软件全部功能的代表性测试用例
(2)专门针对可能受修改影响的软件功能的附加测试
(3)针对被修改过的软件成分的测试。
7.5 确认测试
确认测试也称为验收测试,它的目标是验证软件的有效性。
7.5.3 Alpha和Beta测试
区别:
Alpha测试:由用户在开发环境下进行的测试,在受控的环境中进行。
主要评价软件产品的:FLURPS(即功能、局域化、可使用性、可靠性、性能和支持)
Beta测试:由最终用户在实际使用环境下进行的测试,这些用户定期返回有关错误信息给开发者。只有当α测试达到一定的可靠程度时,才开始 β 测试。
7.6 白盒测试技术
7.6.1 逻辑覆盖
语句覆盖
判定覆盖 :比语句覆盖强,但对程序逻辑的覆盖程度仍不高。
条件覆盖 :判定覆盖不一定包含条件覆盖,条件覆盖也不一定包含判定覆盖。
判定/条件覆盖 :有时判定/条件覆盖也并不比条件覆盖更强。
条件组合覆盖 :条件组合覆盖标准的测试数据并不一定能使程序中的每条路径都执行到。
6. 点覆盖(语句覆盖标准相同)
7. 边覆盖(判定覆盖一致)
8. 路径覆盖
7.6.2 控制结构测试覆盖
- 基本路径测试
基本路径测试是Tom McCabe提出的一种白盒测试技术。
首先计算程序的环形复杂度;
以该复杂度为指南定义执行路径的基本集合;
2.条件测试
从该基本集合导出的测试用例可保证程序中的每条语句至少执行一次,而且每个条件在执行时都将分别取真、假两种值。 - 循环测试
循环测试是一种白盒测试技术,它专注于测试循环结构的有效性。
在结构化的程序中通常只有3种循环,即简单循环、串接循环和嵌套循环。
7.7 黑盒测试技术
7.7.1 等价划分
7.7.2 边界值分析
7.7.3 错误推测
7.8 调试
无论采用什么方法,调试的目标都是寻找软件错误的原因并改正错误。通常需要把系统地分析、直觉和运气组合起来,才能实现上述目标。一般说来,有下列3种调试途径可以采用
(1) 蛮干法
蛮干法可能是寻找软件错误原因的最低效的方法。仅当所有其他方法都失败了的情况下,才应该使用这种方法。按照“让计算机自己寻找错误”的策略,这种方法印出内存的内容,激活对运行过程的跟踪,并在程序中到处都写上 WRITE(输出)语句,希望在这样生成的信息海洋的某个地方发现错误原因的线索。虽然所生成的大量信息也可能最终导致调试成功,但是,在更多情况下这样做只会浪费时间和精力。在使用任何一种调试方法之前,必须首先进行周密的思考,必须有明确的目的,应该尽量减少无关信息的数量。
(2) 回溯法
回溯是一种相当常用的调试方法,当调试小程序时这种方法是有效的。具体做法是,从发现症状的地方开始,人工沿程序的控制流往回追踪分析源程序代码,直到找出错误原因为止。但是,随着程序规模的扩大,应该回溯的路径数目也变得越来越大,以至彻底回溯变成完全不可能了。
(3) 原因排除法
对分查找法、归纳法和演绎法都属于原因排除法。
对分查找法的基本思路是,如果已经知道每个变量在程序内若干个关键点的正确值,则可以用赋值语句或输入语句在程序中点附近“注入”这些变量的正确值,然后运行程序并检查所得到的输出。如果输出结果是正确的,则错误原因在程序的前半部分;反之,错误原因在程序的后半部分。对错误原因所在的那部分再重复使用这种方法,直到把出错范围缩小到容易诊断的程度为止。
归纳法是从个别现象推断出一般性结论的思维方法。使用这种方法调试程序时,首先把和错误有关的数据组织起来进行分析,以便发现可能的错误原因。然后导出对错误原因的一个或多个假设,并利用已有的数据来证明或排除这些假设。当然,如果已有的数据尚不足以证明或排除这些假设,则需设计并执行一些新的测试用例,以获得更多的数据。
演绎法从一般原理或前提出发,经过排除和精化的过程推导出结论。采用这种方法调试程序时,首先设想出所有可能的出错原因,然后试图用测试来排除每一个假设的原因。如果测试表明某个假设的原因可能是真的原因,则对数据进行细化以准确定位错误。
上述3种调试途径都可以使用调试工具辅助完成,但是工具并不能代替对全部设计文档和源程序的仔细分析与评估。如果用遍了各种调试方法和调试工具却仍然找不出错误原因,则应该向同行求助。把遇到的问题向同行陈述并一起分析讨论,往往能开阔思路,较快找出错误原因旦找到错误就必须改正它,但是,改正一个错误可能引入更多的其他错误,以至“得不偿失”。
因此,在动手改正错误之前,软件工程师应该仔细考虑下述3个问题
(1)是否同样的错误也在程序其他地方存在许多情况下,一个程序错误是由错误的逻辑思维模式造成的,而这种逻辑思维模式也可能用在别的地方。仔细分析这种逻辑模式,有可能发现其他错误。
(2)将要进行的修改可能会引入的“下一个错误”是什么改正错误之前应该仔细研究源程序(最好也研究设计文档),以评估逻辑和数据结构的耦合程度。如果所要做的修改位于程序的高耦合段中,则修改时必须特别小心谨慎。
(3)为防止今后出现类似的错误,应该做什么果不仅修改了软件产品还改进了开发软件产品的软件过程,则不仅排除了现有程序中的错误,还避免了今后在程序中可能出现的错误。
7.9 软件可靠性
7.9.1 基本概念
软件可靠性:
程序在给定的时间间隔内,按照规格说明书的规定成功地运行的概率。
软件的可用性:
程序在给定的时间点,按照规格说明书的规定,成功地运行的概率。
7.9.2 估算平均无故障时间的方法
推测错误的产生频度,即推测错误产生的时间间隔。
经验表明,平均无故障时间 MTTF与单位长度程序中剩余的错误数成反比:
估算错误的方法
1)植入错误法
在测试之前由专人在程序中随机地植入一些错误,测试之后,根据测试小组发现的错误中原有的和植入的两种错误的比例,来估计程序中原有错误的总数 ET 。
Mills 将播种模型用于程序中残留错误的估算,称错误植入模型
3) 分别测试法
Hyman 对错误植入模型的改进
两个测试员彼此独立测试同一个程序的两个副本,将把其中一个测试员发现的错误作为有标记的错误,由另一名分析员分析他们的测试结果。
B0:程序中原有的残留错误数
B1: 1 测试员在某一时间内发现的错误数
B2: 2 测试员在同一时间内发现的错误数
bc:两位测试员共同发现的错误数
第8章 维护
软件工程的目的是要提高软件的可维护性,减少软件维护所需要的工作量,降低软件系统的总成本。
8.1 软件维护的定义
软件维护:
在软件已经交付使用之后,为了改正错误或满足新的需要而修改软件的过程。
可分为4项活动:
- 改正性维护
- 适应性维护
- 完善性维护
- 预防性维护
8.2软件维护的特点
8.2.1 结构化维护与非结构化维护差别巨大
8.2.2 维护的代价高昂
8.2.3 维护的问题很多
8.3软件维护过程
1.维护组织 2.维护 告 3.维护的事件流 4.保存维护记录 5.评价维护活动
8.4 软件的可维护性
决定软件可维护性的因素主要有7个:
- 可理解性
- 可测试性
- 可修改性
- 可移植性
- 可重用性
剩余9-13章不考
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!