1 软件工程概述
1.软件危机
软件危机的定义
软件危机(Software Crisis)是指计算机软件的开发和维护过程中所遇到的一系列严重问题。
软件危机的表现
- 对软件开发成本和进度的估算很不准确, 甚至严重拖期和超出预算;
- 无法满足用户需求,导致用户很不满意;
- 质量很不可靠, 经常失效;
- 难以更改、调试和增强;
- 没有适当的文档;
- 软件成本比重上升;
- 软件开发生产率跟不上计算机应用迅速深入的趋势。
产生软件危机的原因
客观上: 软件产品开发的复杂度和难度随软件规模呈指数级别增长。
- 随着软件规模的急速增长, 软件的开发方法已经不适用了。
主观上:软件开发人员缺乏工程性的、系统性的方法论。
- 程序员具有编程的能力, 但对软件开发这一过程性较强的任务却缺乏足够的工程化思维;
- 对软件开发的一些认识的误区:软件神话(Software myths);
- 没有将“软件产品研发”与“程序编码”区分清楚;
- 忽视需求分析、轻视软件维护。
消除软件危机的途径
总之,要从技术和管理两方面,既要有技术措施(方法和工具),又要有必要的组织管理措施。
2.软件生命周期
(包含的阶段,不同阶段与不同文档的对应关系,不同阶段所涉及的图形建模工具)
阶段 | 文档 | 图形建模工具 |
---|---|---|
问题定义 | / | / |
可行性研究 | 可行性研究报告 | 系统流程图、数据流图、数据字典 |
需求分析 | 软件需求规格说明书 | 实体-联系图(ER图)、状态转化图、层次方框图、Warnier图、IPO图 |
总体设计 | 概要设计说明书 | 层次图、HIPO图、结构图 |
详细设计 | 详细设计说明书 | 程序流程图、盒图(N-S图)、PAD图、判定表、判定树、过程设计语言(PDL)(伪码)、Jackson图、流图 |
编码和单元测试 | 测试计划、测试分析报告 | / |
综合测试 | 测试计划、测试分析报告 | / |
软件维护 | 软件维护手册、软件问题报告、软件修改报告 | / |
3.几类经典软件工程模型
1 瀑布模型(Waterfall Model)
- 提供了软件过程模型的基本框架(模板)。
- 强调了每一阶段活动的严格顺序。
- 质量保证观点:以经过评审确认了的阶段工作产品(文档)驱动下一阶段的工作,便于管理。
- 是一种整体开发模型,程序的物理实现集中在开发阶段的后期,用户在最后才能看到自己的产品。
瀑布模型的优缺点
瀑布模型适合于用户需求明确、完整、无重大变化的软件项目开发。瀑布模型的成功在很大程度上是由于它基本上是一种文档驱动的模型。
“瀑布模型是由文档驱动的”这个事实也是它的一个主要缺点:
- 实际项目并不一定按照该模型给出的顺序进行;
- 用户常常难以清楚地给出所有需求;
- 用户必须有耐心,等到系统开发完成。
2 快速原型模型 (Rapid Prototype Model)
在用户不能给出完整、准确的需求说明,或者开发者不能确定算法的有效性、操作系统的适应性或人机交互的形式等许多情况下,可以根据用户的一组基本需求,快速建造一个原型(可运行的软件),然后进行评估,进一步精化、调整原型,使其满足用户的要求,也使开发者对将要做的事情有更好的理解。
原型模型存在的问题
⑴ 为了使原型尽快的工作,没有考虑软件的总体质量和长期的可维护性。
⑵ 为了演示,可能采用不合适的操作系统、编程语言、效率低的算法,这些不理想的选择成了系统的组成部分。
⑶ 开发过程不便于管理。
有效的使用原型模式
建造原型仅是为了定义需求,之后就被抛弃(或被部分抛弃),实际的软件在充分考虑了质量和可维护性之后才被开发。
3 增量模型 (Incremental Model)
是一种渐进地开发逐步完善的软件版本的模型。
反复的应用瀑布模型的基本成分和原型模型的迭代特征,每一个线型过程产生一个“增量”的发布或提交,该增量均是一个可运行的产品。
早期的版本实现用户的基本需求,并提供给用户评估的平台。
增量模型的优点
- 在较短时间内向用户提交可完成部分工作的产品,并分批、逐步地向用户提交产品。从第一个构件交付之日起,用户就能做一些有用的工作。
- 整个软件产品被分解成许多个增量构件,开发人员可以一个构件一个构件地逐步开发。
- 逐步增加产品功能可以使用户有较充裕的时间学习和适应新产品,从而减少一个全新的软件可能给客户组织带来的冲击。
- 采用增量模型比采用瀑布模型和快速原型模型需要更精心的设计,但在设计阶段多付出的劳动将在维护阶段获得回报。
增量模型的困难
- 在把每个新的增量构件集成到现有软件体系结构中时,必须不破坏原来已经开发出的产品。此外,必须把软件的体系结构设计得便于按这种方式进行扩充,向现有产品中加入新构件的过程必须简单、方便,也就是说,软件体系结构必须是开放的。
- 开发人员既要把软件系统看作整体。又要看成可独立的构件,相互矛盾。
- 多个构件并行开发,具有无法集成的风险。
4 螺旋模型 (Spiral Model)
- 软件风险是任何软件开发项目中都普遍存在的实际问题,项目越大,软件越复杂,承担该项目所冒的风险也越大。
- 对于复杂的大型软件,开发一个原型往往达不到要求。螺旋模型将瀑布模型和增量模型结合起来,加入了风险分析。在该模型中,软件开发是一系列的增量发布,早期的迭代中,发布的增量可能是一个纸上的模型或原型,在以后的迭代中,逐步产生系统更加完善的版本。
- 螺旋模型的基本思想是降低风险。
螺旋模型的优点
- 对可选方案和约束条件的强调有利于已有软件的重用,也有助于把软件质量作为软件开发的一个重要目标
- 减少了过多测试或测试不足
- 维护和开发之间并没有本质区别
螺旋模型的特点
- 风险驱动,需要相当丰富的风险评估经验和专门知识,否则风险更大
- 主要适用于内部开发的大规模软件项目,随着过程的进展演化,开发者和用户能够更好的识别和对待每一个演化级别上的风险
- 随着迭代次数的增加,工作量加大,软件开发成本增加
5 喷泉模型(Fountain Model)
特点:主要用于支持面向对象开发过程,体现了软件创建所固有的迭代和无间隙的特征。
6 Rational统一软件开发过程 (RUP)
每个周期划分为初始、细化、构造和移交四个阶段,每个阶段围绕着五个核心工作流(需求、分析、设计、实现、测试)分别迭代。
在每个阶段的每次迭代的最后,用例模型、分析模型、设计模型、实现模型都会增量,每个阶段结束的里程碑处,管理层做出是否继续、进度、预算、是否给下一阶段提供资助等决定。
不同阶段工作流的侧重点不同,前两阶段大部分工作集中在需求、分析和架构设计上;在构造阶段,重点转移到详细设计、实现和测试上。
7 敏捷 (灵活, AGILE) 过程与极限编程
8 微软过程
2 可行性分析
4.涉及哪些方面的可行性
(1) 技术可行性
度量一个特定技术信息系统解决方案的实用性及技术资源的可用性。
考虑的问题
(1)开发风险分析
(2)资源分析
(3)相关技术的发展(现有技术能否实现新系统,技术难点、建议采用技术的先进性)
(2) 经济可行性
度量系统解决方案的性能价格比。
考虑的问题
成本/效益分析(开发、运行的成本/效益):
- 有形成本、效益
- 无形成本、效益
价值和成本的关系:
- 质量与价值、成本的关系
- 价值/成本的均衡
(3) 操作可行性
- 用户使用可能性
- 时间进度可行性
- 组织和文化上的可行性
5.分层DFD
数据流图(DFD)
数据流图(DFD)是一种图形化技术,它描绘信息流和数据从输入移动到输出的过程中所经受的变换。
在数据流图中没有任何具体的物理部件,它只是描绘数据在软件中流动和被处理的逻辑过程,是系统逻辑功能的图形表示。
设计数据流图时只需考虑系统必须完成的基本逻辑功能,完全不需要考虑怎样具体地实现这些功能,所以它也是今后进行软件设计的很好的出发点。
分层数据流图(分层DFD)
为了表达数据处理过程的数据加工情况,需要采用层次结构的数据流图。按照系统的层次结构进行逐步分解,并以分层的数据流图反映这种结构关系,能清楚地表达和容易理解整个系统。
- 在多层数据流图中,顶层流图仅包含一个加工,它代表被开发系统。它的输入流是该系统的输入数据,输出流是系统所输出数据。
- 底层流图是指其加工不需再做分解的数据流图,它处在最底层。
- 中间层流图则表示对其上层父图的细化。它的每一加工可能继续细化,形成子图。
分层DFD的优点
便于实现:采用逐步细化的扩展方法,可避免一次引入过多的细节,有利于控制问题的复杂度;
便于使用:用一组图代替一张总图,方便用户及软件开发人员阅读。
3 需求分析
6.需求分析建模的结构化方法 P62
- (1) 信息域,数据模型(ER图)
- (2) 软件功能,功能模型(数据流图)
- (3) 软件行为,行为模型(状态/活动图)
- (4) 分层细化
具体见书、课件或前面的笔记。
3.4 实体-联系图 (ER图)
2.4 数据流图
3.6 状态转换图
7.接口需求 P57
常见的接口需求有:
- 用户接口需求
- 硬件接口需求
- 软件接口需求
- 通信接口需求
8.需求分析阶段所涉及的建模工具图形
- 实体-联系图 (ER图)
- 状态转换图
- 层次方框图
- Warnier图
- IPO图
具体见书、课件或前面的笔记。
3.4 实体-联系图 (ER图)
3.6 状态转换图
3.7 层次方框图、Warnier图、IPO图
5 总体设计
9.模块划分原理、耦合和内聚 P97-99
模块划分原理
软件设计中应该低耦合、高内聚:
- 追求尽可能松散耦合,避免强耦合,这样模块间的联系就越小,模块的独立性就越强,对模块的测试、维护就越容易。因此建议:尽量使用数据耦合,少用控制耦合,限制公用耦合,完全不用内容偶合。
- 力求做到高内聚,尽量少用中内聚,不用低内聚。
耦合
耦合:指软件结构内不同模块彼此之间相互依赖(连接)的紧密程度。模块的偶合分四类:
1)数据耦合
两个模块之间只是通过参数交换信息,而且交换的信息仅仅是数据。
数据耦合是最低程度的耦合。
2)控制耦合
两个模块之间所交换的信息包含控制信息。
控制耦合是中等程度的耦合。
3)公用耦合
两个或多个模块通过一个公共区相互作用时的耦合。
公共区可以是:全程数据区、共享通信区、内存公共覆盖区、任何介质上的文件、物理设备等。
软件结构中存在大量的公用耦合时会给诊断错误带来困难。
4)内容耦合
一个模块与另一个模块的内容直接发生联系。
内容耦合对维护会带来严重的困难。
内聚
内聚:一个模块内部各个元素彼此结合的紧密程度。它是衡量一个模块内部组成部分间整体统一性的度量。常见的内聚有七类:
1)功能内聚(Functional Cohesion)
如果一个模块内所有处理元素完成一个,而且仅完成一个功能,则称为功能内聚。
功能内聚是最高程度的内聚。但在软件结构中,并不是每个模块都能设计成一个功能内聚模块。
2)顺序内聚(Sequential Cohesion)
如果一个模块内处理元素和同一个功能密切相关,而且这些处理元素必须顺序执行,则称为顺序内聚。
通常,顺序内聚中一个处理元素的输出是另一个处理元素的输入。
3)通信内聚(Communicational Cohesion)
如果一个模块中所有处理元素都使用同一个输入数据和(或)产生同一个输出数据,称为通信内聚。
通信内聚有时也称为数据内聚。
4)过程内聚(Procedural Cohesion)
如果一个模块内的处理元素是相关的,而且必须以特定的次序执行,称为过程内聚。
过程内聚与顺序内聚的区别是:顺序内聚中是数据流从一个处理单元流到另一个处理单元,而过程内聚是控制流从一个动作流向另一个动作。
5)时间内聚(Temporal Cohesion)
如果一个模块包含的任务必须在同一段时间内执行,称为时间内聚。也称为瞬时内聚。
例如,完成各种初始化工作的模块,或者处理故障的模块都存在时间内聚。
6)逻辑内聚(Logical Cohesion)
如果模块完成的任务在逻辑上属于相同或相似的一类,称为逻辑内聚。
对逻辑内聚模块的调用,常常需要有一个功能开关,由上层调用模块向它发出一个控制信号,在多个关联性功能中选择执行某一个功能。
这种内聚较差,增加了模块之间的联系,不易修改。
7)偶然内聚(Coincidental Cohesion)
如果一个模块由完成若干毫无关系的功能处理元素偶然组合在一起的,就叫偶然内聚。
偶然内聚是最差的一种内聚。
常犯这种错误的一种情况是:有时在写完程序后,发现一组语句在多处出现,于是为了节省空间而将这些语句作为一个模块设计,就出现偶然内聚。
10.耦合度(松散性)、内聚度(高低)P97-99
耦合度(松散性)
数据耦合 < 控制耦合 < 公用耦合 < 内容耦合
内聚度(高低)
(高内聚)功能内聚 > 顺序内聚 >
(中内聚)通信内聚 > 过程内聚 >
(低内聚)时间内聚 > 逻辑内聚 > 偶然内聚
11.作用域、控制域 P100-101
- 作用域:受该模块内一个判定影响的所有模块的集合。
- 控制域:模块本身以及所有从属于它的模块的集合。
模块的作用域应该在控制域之内。
12.软件层次结构的深度、宽度、扇入、扇出 P100
- 深度:软件结构中控制的层数;
- 宽度:软件结构内同一个层次上的模块总数的最大值;
- 扇出:一个模块直接控制(调用)其它模块的数目;
- 扇入:一个模块被其它模块调用的数目。
深度、宽度、扇出和扇入都应适当。
6 详细设计
13.环形复杂度的计算,三种计算方法 P137-138
1)环形复杂度 V(G)等于流图中的区域数;
2)环形复杂度 V(G)=E-N+2,其中E是流图中边的条数,N是结点数;
3)环形复杂度 V(G)=P+1,其中P为流图中判定结点的数目。
例题见书、课件或前面的笔记。
6.5 程序复杂度的定量度量 > McCabe方法 > 计算环形复杂度的方法
14.程序流程图与NS图的互相转化 P124-126
具体见书、课件或前面的笔记。
6.3 过程设计的工具
6.3.1 程序流程图
6.3.2 盒图(N-S图)
书、课件或前面的笔记都没有例题。
15.判定表和判定树 P127-128
具体见书、课件或前面的笔记。
6.3 过程设计的工具
6.3.4 判定表
6.3.5 判定树
16.面向数据结构的Jackson图 P130-132
具体见书、课件或前面的笔记。
6.4 面向数据结构的设计方法
6.4.1 Jackson图
6.4.2 改进的Jackson图
7 软件实现
17.测试过程所涉及的类型 P151-152
1.模块测试(单元测试)
模块测试又称单元测试,它把每个模块作为单独的实体来测试。
具体见书、课件或前面的笔记。
7.3 单元测试
2.子系统测试(集成测试)
子系统测试是把经过单元测试的模块放在一起形成一个子系统来测试。
3.系统测试(集成测试)
系统测试是把经过测试的子系统装配成一个完整的系统来测试。
具体见书、课件或前面的笔记。
7.4 集成测试
4.验收测试(确认测试)
验收测试把软件系统作为单一的实体进行测试(利用用户的实际数据测试)。
具体见书、课件或前面的笔记。
7.5 确认测试
5.平行运行
平行运行是同时运行新开发出来的系统和将被它取代的旧系统,以便比较新旧两个系统的处理结果。
18.渐增式测试的优先策略 P157-159
使用渐增式测试方法把模块结合到软件系统中去时,有自顶向下和自底向上两种集成方法。
自顶向下集成
自顶向下集成是一种递增的装配软件结构的方法,这种方法应用非常广泛。它需要存根程序,但是不需要驱动程序。这种方法的思想是:从主控模块(主程序)开始,沿软件的控制层次向下移动,逐渐把各个模块结合起来。
在自顶向下结合方法中,如何将所有模块组装到软件结构中,又有两种方法:
1)深度优先策略
先组装软件结构的一条主控制通路上的所有模块,选择哪条主控制通路,具有较大的任意性。
2)宽度优先策略
沿着软件结构水平地移动,把处于同一个层次的所有模块组装起来。
自底向上集成
自底向上集成方法是从软件结构最底层模块开始进行组装和测试,它与自顶向下结合方法相反,需要驱动程序,不需要存根程序。
19.黑盒测试、白盒测试
黑盒测试、白盒测试的定义和区别
书、课件或前面的笔记都没有找到这项内容。
(不过代码审计的笔记有)
白盒测试的逻辑覆盖 P162-165
- 语句覆盖:设计的测试用例能使程序中每条语句至少执行一次。
- 判定覆盖:选取足够的测试用例,使得程序中每个判断的可能结果都至少执行一次,也就是说使程序的每个判断分支至少通过一次。
- 条件覆盖:选择足够的测试用例,使得程序中每个判定表达式的每个条件都取到各种可能的结果。
- 判定/条件覆盖:选取足够的测试用例使得同时满足判定覆盖和条件覆盖的要求。
- 条件组合覆盖:选取足够的测试用例,使得每个判定表达式中条件的各种可能的组合都至少出现一次。
- 点覆盖:选取足够多的测试用例,使得程序执行路径至少经过程序图中每个节点一次。
- 边覆盖:选取足够多的测试用例,使得程序执行路径至少经过程序图中每条边一次。
- 路径覆盖:选取足够多的测试用例,使得程序的每条可能路径都至少执行一次。
黑盒测试
具体见书、课件或前面的笔记。
7.6 白盒测试技术
7.7 黑盒测试技术
20.等价类划分、边界值分析 P172-175
黑盒测试的等价类划分
等价类划分的思想:如果将所有可能的输入数据(有效的和无效的)划分为若干个等价类,就可以假定用每一个等价类中的代表值作为测试用例来进行测试时,等价于用该类中所有值进行了测试。
用等价类划分设计测试用例时,主要分两步:
1)等价类划分
划分等价类需要经验,以下给出一些规则:
- A.如果某输入条件规定了输入的范围,那么可以划分为一个有效的等价类和两个无效的等价类。
- B.如果某个输入条件规定了一组可能的值,且程序可以对不同的值作出不同的处理,那么可以为每种值确定一个有效的等价类,同时还有一个无效等价类。
2)确定测试用例
- A.给每个等价类规定一个唯一的编号;
- B.设计一个新的测试用例,使其尽可能多地覆盖未被覆盖过的有效等价类。重复此步,直至所有有效等价类被覆盖;
- C.设计一个新的测试用例,使其覆盖而且只覆盖一个尚未被覆盖的无效等价类。重复此步,直到所有无效等价类被覆盖。
通常程序发现一类错误后,就报出错信息,不再检查其它类错误,所以设计测试用例时,一次只覆盖一个无效等价类。
黑盒测试的边界值分析
程序通常在处理边缘情况时容易出现错误,如等价类与等价类之间的边界值。所以在设计测试用例时,使用正好等于、正好大于、正好小于边界值的数据进行测试,发现程序错误的概率较大。
在实际设计测试方案时,常常结合使用等价划分和边界值分析两种技术,把一些等价类的边界值作为测试用例进行测试。
例题见书、课件或前面的笔记。
7.7 黑盒测试技术
21.软件可靠性和可用性的联系区别 P179-180
对故障可修复系统,应同时使用可靠性和可用性来衡量。
软件可靠性:是程序在给定的时间间隔内,按照规格说明书的规定成功地运行的概率。
软件可用性:程序在给定的时间点,按照规格说明书的规定,成功地运行的概率。
可靠性和可用性的区别是:可靠性是在0到t时间间隔内,系统没有失效的概率。而可用性是在t时刻,系统是正常运行的概率。
如果在t时刻,系统是可用的,则有两种可能:
- 1)在0到t时刻这段时间内,系统一直没有失效(可靠);
- 2)在0到t时刻这段时间内失效过,但是系统修复后运行到t时刻时情况良好。
8 软件维护
22.维护类型 P189-190
1)改正性维护
交付给用户使用的软件,即使通过严格的测试,仍可能有一些潜在的错误在用户使用的过程中发现和修改。诊断和改正错误的过程称为改正性维护。
2)适应性维护
随着计算机的飞速发展,新的硬件系统和外部设备时常更新和升级,一些数据库环境、数据输入/输出方式、数据存储介质等也可能发生变换。为了使软件适应这些环境变化而修改软件的过程叫做适应性维护。
3)完善性维护(占软件维护工作的大部分)
在软件投入使用过程中,用户可能还会有新的功能和性能要求,可能会提出增加新功能、修改现有功能等要求。为了满足这类要求而进行的维护称为完善性维护。
4)预防性维护
为了改进软件未来的可维护性或可靠性,或者为了给未来的改进奠定更好的基础而进行的修改,称为预防性维护。这种维护活动在实践中比较少见。
23.非结构化维护和结构化维护 P190
1. 非结构化维护
如果软件配置的唯一成分是代码,则维护从评价程序代码开始。对软件结构、数据结构、系统接口、设计约束等则常产生误解,不能进行回归测试,维护代价大。
2. 结构化维护
有完整的软件配置,维护从评价设计文档开始,确定软件结构、性能和接口特点,先修改设计,接着修改代码,再进行回归测试。
24.软件维护的有形代价与无形代价 P190-191
有形代价指软件维护的费用开支。
无形代价:
- 因为可用资源必须供维护任务使用,以致耽误甚至丧失了开发的良机。
- 当一些看起来合理的要求不能及时满足时,会引起用户的不满。
- 改动软件可能会引入新的错误,使软件质量下降。
- 把许多软件工程师调去从事维护工作,势必影响开发工作。