软件工程笔记
软件与软件工程的概念
1.1 软件的概念、特性和分类
概念
$$
软件(与硬件相互依存)
\begin{cases}
程序:按事先设计的功能和性能要求执行的指令序列
\newline
数据:使程序能正常操纵信息的数据结构
\newline
文档:与程序开发、维护和使用有关的图文材料
\end{cases}
$$
特性
形态特性:无形的逻辑实体
智能特性:复杂的智力产品
开发特性:软件的开发至今没有完全摆脱手艺的开发方式
质量特性:目前还没有得到完全没有缺陷的软件产品
生产特性:无明显制造过程,按需制作
管理特性:开发管理特性
环境特性:依赖编译环境
维护特性:比硬件更加复杂的维护
废弃特性:没有老化而被废弃的问题,但是存在退化问题
应用特性:无可取代的地位
分类
系统软件:底层软件,服务于其他程序的程序
应用软件:解决特定业务所需要的独立应用程序
工程/科学软件:“数值计算”
嵌入式软件:某个产品中特定功能的软件
产品线软件:为多个不同用户提供特定功能
Web/移动应用软件:App
人工智能软件:智能
1.2 软件危机与软件工程
软件危机:计算机软件的开发、运行和维护过程所遇到的一系列严重问题
主要表现(征兆):软件发展速度远远滞后于硬件的发展(判断时只需判断是否对该软件有负面反馈)
原因:开发周期长、成本高、质量差、维护困难
1.3 软件工程的目标
运用先进的开发技术和管理方法提高软件的质量和生产率(花更少的代价做最好产品)
功能性、可靠性、易于使用性、效率、可维护性、可移植性
1.4 软件生存期
三时期:软件定义(做什么)—->软件开发(如何做)—->运行维护(使软件持久地满足用户的需要)
1.5 软件工程方法概述
软件开发全过程中使用的一整套技术方案成为方法学(范型)
方法学三要素:过程、方法和工具
传统方法、面向对象方法、面向服务方法、面向数据方法、形式化方法
1.6 软件工具概述
支持软件开发过程的工具、支持软件维护过程的工具、支持软件管理过程和支持过程的工具
1.7 软件工程知识体系及知识域
四个基础类的知识域:软件工程经济学、计算基础、工程基础和教学基础
小测验
1、( D ) 下列的叙述中,_ (1)_ 不是软件危机的征兆。
A.软件产品往往不满足用户的真实需求
B.软件产品常常是不可维护的
C.软件开发成本和进度的估计不准确.
D.随着软件规模的增大,其复杂性不断增加
2、( A ) 下列的叙述中,(2)_ 不是软件危机发 生的主要原因。
A.缺乏可视化的开发工具
B.随着软件规模的增大,其复杂性不断增加
c.需求说明不充分或存在错误
D.软件开发过程不规范,缺少方法论和规范的指导
3、( A ) 下面的_ (3)_ 不再是现代软件 工程师关注的问题。
A.为什么计算机硬件的成本这么高?
B.为什么软件需要很长时间才能完成?
c.为什么开发一个软件的成本这么高?
D.为什么不能在产品发布前去除软件错误?
4、( C )软件会逐渐退化而不会磨损,其原因在于_ (4)_ 。
A.软件通常暴露在恶劣的环境下
B.软件错误通常发生在使用之后
C.不断的变更使组件接口之间引起错误
D.软件备件很难订购
5、( B ) 软件工程的基本目标是_ (5)_ 。
A.消除软件固有的复杂性
B.开发高质量的软件
C.努力发挥开发人员的创造性潜能
D.更好地维护正在使用的软件产品
软件生存期模型
2.1 瀑布模型
1)阶段间具有顺序性和依赖性。其中包含两重含义:
必须等前一阶段的工作完成之后,才能开始后一阶段的工作。
前一阶段的输出文档就是后一阶段的输入文档。
2)推迟实现的观点。
瀑布模型在编码之前设置了系统分析和系统设计的各个阶段。分析与设计阶段的基本任务规定,在这两个阶段主要考虑目标系统的逻辑模型,不涉及软件的物理实现。
清楚地区分逻辑设计与物理设计,尽可能推迟程序的物理实现,是按照瀑布模型开发软件的一条重要的指导思想。
3)质量保证的观点。
每个阶段都必须完成规定的文档,没有交出合格的文档就是没有完成该阶段的任务。
每个阶段结束前都要对所完成的文档进行评审,以便及时发现问题,改正错误。
在实际开发过程中,瀑布模型是带有反馈的,图中实线箭头表示开发过程,虚线箭头表示维护过程。当在后面阶段发现前面阶段的错误时,需要沿图中左侧的反馈线返回前面的阶段,修正前面阶段的产品之后再回来继续完成后面阶段的任务。
瀑布模型的变体:V模型
优点:可强迫开发人员采用规范化的方法、严格地规定了每个阶段必须提交的文档、要求每个阶段交出的所有产品都必须是经过验证(评审)的。
缺点:由于瀑布模型几乎完全依赖于书面的规格说明,很可能导致最终开发出的软件产品不能真正满足用户的需要。如果需求规格说明与用户需求之间有差异,就会发生这种情况、瀑布模型只适用于项目开始时需求已确定的情况。
2.2 快速原型模型
快速原型是快速建立起来的可以在计算机上运行的程序,它所能完成的功能往往是最终产品功能的一个子集。
优点:
有助于满足用户的真实需求。
原型系统已经通过与用户的交互而得到验证,据此产生的规格说明文档能够正确地描述用户需求。
软件产品的开发基本上是按线性顺序进行。
因为规格说明文档正确地描述了用户需求,所以在开发过程的后续阶段不会因发现规格说明文档的错误而进行较大的返工。
开发人员通过建立原型系统已经学到了许多东西,因此,在设计和编码阶段发生错误的可能性比较小,这自然减少了在后续阶段需要改正前面阶段所犯错误的可能性。
快速原型的本质是“快速”。开发人员应该尽可能快地建造出原型系统,以加速软件开发过程,节约软件开发成本。原型的用途是获知用户的真正需求,一旦需求确定了,原型就可以抛弃,当然也可以在原型的基础上进行开发。
2.3 增量模型
使用增量模型开发软件时,把软件产品作为一系列的增量构件来设计、编码、集成和测试。
如果客户要求你在一个短期很难完成的产品,那么就适合增量模型,先提交一个或几个增量,后续再做补充
使用增量模型时,第一个增量构件往往实现软件的基本需求,提供最核心的功能。;第二个增量构件提供更完善的编辑和文档生成功能;第三个增量构件实现拼写和语法检查功能;第四个增量构件完成高级的页面排版功能。
优点:风险低、适用于紧急项目、由于核心功能是最先交付的,后续测试多,故不易失败、制作者有较长时间学习,减少失败风险
注意:在把每个新的增量构件集成到现有软件体系结构中时,必须不破坏原来已经开发出来的产品;软件体系结构必须是开放的,即向现有产品中加入新构件的过程必须简单、方便。
2.4 螺旋模型
螺旋模型最初是Boehm于1988年提出来的。该模型将瀑布模型与快速原型模型结合起来,并且加入两种模型均忽略了的风险分析。螺旋模型的基本思想是,使用原型及其他方法来尽量降低风险。
理解这种模型的一个简便方法,是把它看作在每个阶段之前都增加了风险分析过程的快速原型模型,如图2-7所示。
优点:
对可选方案和约束条件的强调有利于已有软件的重用,也有助于把软件质量作为软件开发的一个重要目标。
减少了过多测试或测试不足所带来的风险。
在螺旋模型中维护只是模型的另一个周期,因而在维护和开发之间并没有本质区别。
注意:螺旋模型是风险驱动的,因此要求软件开发人员必须具有丰富的风险评估经验和这方面的专门知识。
2.5 喷泉模型
喷泉模型是典型面对对象生命周期模型
“喷泉”一词体现了迭代和无间隙特性。图中代表不同阶段的圆圈相互重叠,这明确表示两个活动之间存在重叠。用面向对象方法开发软件时,在分析、设计和编码等项开发活动之间并不存在明显的边界,而各阶段在表示方法上的一致性也保证了各项开发活动之间的无缝过渡。图中一个阶段内的向下箭头代表该阶段中的迭代或求精。
2.6 统一过程
统一建模语言UML
初始阶段 —-> 细化节点 —-> 构造(构建)阶段 —-> 移交阶段
2.7 基于构件的开发模型
2.8 敏捷过程
一种较为广泛的敏捷过程—->极限编程过程
小测试
1、( A )某公司要开发一个软件产品,产品的某些需求是明确的,而某些需求则需要进一步细化。由于市场竞争的压力,产品需要尽快上市,则开发该软件产品最不适合采用_ (1)_ 过程模型。
(1): A.瀑布 B.快速原型 C.增量 D.螺旋
2、( D ) 某软件公司欲开发-一个基于Web的考勤管理系统。在项目初期,客户对系统的基本功能、表现形式等要求并不明确,在这种情况下,采用_ (2)_ 比较合适。
(2): A.瀑布模型 B.螺旋模型 C.喷泉模型 D.极限编程
3 4、( A )( C )某开发小组欲为一公司开发一个产品控制软件,监控产品的生产和销售过程,从购买各种材料开始,到产品的加工和销售进行全程跟踪。购买材料的流程、产品的加工过程以及销售过程可能会发生变化。该软件的开发最不适宜采用_ (3)_ 模型,主要是因为这种模型_ (4)_
(3): A.瀑布 B.快速原型 C.增量 D.喷泉
(4): A.不能解决风险 B.不能快速提交软件C.难以适应变化的需求 D.不能理解用户的需求
5、( C )新软件项目与过去成功开发过的一个项目类似,但规模更大,此时比较适合使用(5) 进行项目开发设计。
(5): A.快速原型法 B .变换模型 C.瀑布模型 D.螺旋模型
6、( B ) 某开发小组欲开发一个超大规模软件:使用通信卫星,在订阅者中提供、监视和控制移动电话通信,则最不适宜采用_(6) _过程模型。
(6): A.瀑布 B.快速原型 C.螺旋 D.喷泉
7 8、( C ) ( A ) 若用户需求不清晰且经常发生变化,但系统规模不太大且不太复杂,则最适宜采用_ (7)_ 过程模型,对于数据处理领域的问题,若系统规模不太大且不太复杂,需求变化也不大,则最适宜采用_ (8)_过程模型。
(7): A.瀑布模型B.螺旋模型C.快速原型D.喷泉模型
(8): A.瀑布模型 B.螺旋模型 C.快速原型 D.喷泉模型
9、( A ) 支持面向对象技术的软件过程模型是_ (9)_
(9): A.喷泉模型 B .螺旋模型 C.增量模型 D.瀑布模型
10、( C ) 某企业拟开发-个企业信息管理系统,系统功能与多个部门的业务相关。现希望该系统能够尽快投入使用,系统功能可以在使用过程中改善,则最适宜采用的软件过程模型为_ (10)_ 。
(10): A.瀑布模型 B. 原型模型 C.增量模型 D.螺旋模型
软件需求获取与结构化分析
任务
- 发现和分析问题
- 与用户交流
- 从数据、过程和接口三个方面观察问题的不同侧面
- 将需求文档化:用例、决策表、决策树等
原则
- 深入浅出(获取的需求尽可能的详细)
- 以流程为主线的原则
结构化分析方法
结构化模型
核心是数据字典,下面三种图围绕该核心
- 数据流图(DFD):描述数据在系统中如何被传送和变换,以及子功能
- 实体-关系图(E-R图):描述对象以及数据对象之间的关系,用于数据建模
- 状态迁移图(STD):描述系统对外部事件如何响应
基本符号
多个数据流之间的关系
环境图(顶层数据流图)
数据流图的分层
- 将顶层数据流图进行功能分解得到一层数据流图
- 将一层数据流图的功能进行进一步分解得到二层数据流图
数据建模
- E-R图
行为建模
- 上面是有触发事件行为的状态图,当然也可以有无事件触发的
- 事件:事件说明[守卫条件]/动作表达式
- 事件说明的语法为:事件名(参数表)
- 守卫条件是一个布尔表达式,优先看事件说明的真值
- 动作表达式是一个过程表达式,当状态开始时执行该表达式
数据字典
- 词条描述:数据流词条、数据元素词条、数据存储文件词条、加工词条、数据源点及汇点词条
- 数据结构
- 定义式
- Warnier图
- 下图给出了“存折”的Warnier图。在图中,用花括号“{”表示层次关系,在同一括号下,自上到下是顺序排列的数据项。在有些数据项的名字后面附加了圆括号,给出该数据项重复的次数。如“字母(2,24)”表示字母有2~24个;“整数(11)”表示数字占11位;“浮点数(9,2)”表示浮点数整数部分占7位,小数部分占2位;“摘要(0,1)”表示摘要可有可无,若有就占一栏。此外,用符号⊕表示二者选一的选择关系
- 定义式
加工规格说明
- 决策表
- 决策树
系统需求规格说明
- 需求规格说明(SRS)
- 数据需求说明(DRD)
- 完整性、无歧义性、一致性、可验证性、可修改性、可追踪性
需求评审
需求管理
- 需求跟踪
- 需求变更管理
结构化设计方法
设计原则
分而治之
模块独立性
提高抽象层次
复用性设计
灵活性设计
模块化设计
- 结构:网状与树状
- 结构图:菱形有条件调用,扇形表示反复调用;信息流(数据信息[空心圆]和控制信息[实心圆])
体系结构设计
- 变换型数据流与变换型系统结构图(数据变换)
- 事务型数据流与事务型系统结构图(事务变换)
模块间的耦合和内聚
耦合
低 耦合性 高 非直接耦合 数据耦合 标记耦合 控制耦合 外部耦合 公共耦合 内容耦合 强 模块独立性 弱
内聚
高 内聚性 低 功能内聚 信息内聚 通信内聚 过程内聚 时间内聚 逻辑内聚 巧合内聚 强 模块独立性 弱
程序化程序设计
- 程序流程图
- 顺序型
- 选择型
- 先判定型(while)
- 后判定型(until)
- 多情况型(case)
- N-S图
- 每个矩形框都定义了功能域,清晰可见
- 转移不能任意规定
- 很容易确定局部数据和全局数据的作用域
- 容易表现嵌套关系,也可以表示模块的层次
- PAD图
- 结构清晰
- 易于自动装换成高级语言源程序
- 既可以表示程序逻辑,也可以描绘数据结构
- 支持自顶向下、逐步求精的方法
- 伪代码
- 简单陈述句结构:避免复合语句
- 判定结构:IF-THEN-ELSE 或者 CASE-OF
- 重复结构:WHILE-DO 或者 REPEAT-UNTIL
- 自顶向下、逐步细化
软件测试方法
这里需要特别注意一下:确认测试、验证测试、集成测试、单元测试都是软件测试的步骤,而不是测试的方法
黑盒测试
测试人员不清楚软件内部的构造,只通过软件说明书来测试程序是否合格(类似于王大测试计组实验,不知道里面是怎么实现的,只在乎输入和输出)
白盒测试
与黑盒测试相反,直到程序的内部工作流程图,然后精心造样例来发现错误
- 逻辑覆盖
- $\vee \rightarrow AND$ $\wedge \rightarrow OR$
- 将程序段的每一处分支都表示出来
- 语句覆盖
- 格式:【输入的(x,x,x),输出的(x,x,x)】覆盖【$L_i$】
- 也就是说要构造若干组数据使得能覆盖某一条线路$L_i$
- 判定(分支)覆盖
- 构造若干数据使得覆盖条件分支的真和假分支至少经历一次
- 条件覆盖
- 构造若干数据使得每个判断里面的语句的子语句的真和假至少经过一次
- 但是可能不会覆盖所有的判定的分支
- 判定-条件覆盖
- 将上述两种覆盖结合
- 条件组合覆盖
- 对每个判断里面的子语句进行真假的组合得到$2^n$个组合,然后构造使得能覆盖这些组合
- 比如$T_1T_2 ,\overline{T_1}T_2 ,T_1\overline{T_2}, \overline{T_1T_2}$ ,就是能全部出现在测试样例中
- 路径覆盖
- 能覆盖所有的路径
路径覆盖
- 程序控制流程图
- 程序环路的复杂性
- $V(G) = E-N+2$
- $E:$边数 , $N:$点数(欧拉公式)
- $V(G) = P+1$
- $P:$控制流图中的判定节点数
- $V(G) = E-N+2$
- 独立路径
- 包括一组以前没有处理的语句或条件的一条路径,不唯一
- 步骤
- 由过程到处控制流图
- 计算得到的控制流图的环路复杂性
- 准备测试用例,确保基本路径集中的每一条路径的执行
- 图形矩阵
- 邻接矩阵
黑盒测试
- 等价类的划分
- 划分等价类:有效等价类和无效等价类
- 确定测试用例
- 为每一个等价类规定一个唯一的编号
- 设计一个新的测试用例,使其尽可能多地覆盖尚未被覆盖的有效等价类,直到所有有效等价类都被覆盖为止
- 设计一个新的测试用例,使其仅覆盖一个尚未被覆盖的无效等价类,直到所有无效等价类都被覆盖为止
- 边界值分析
- 相对与输入等价类和输出等价类而言,稍微高于边界值或者低于边界值的特定的情况
软件测试的策略
$4$个步骤:单元测试、组装测试、确认测试、系统测试
- 单元测试(模块测试)
- 模块接口测试、局部数据结构测试、路径测试、错误处理测试、边界测试
- 驱动模块:相当于被测模块的主程序,接受数据,把数据传送给被测模块,最后输出结果
- 桩模块(存根模块):用以代替被测模块调用的子模块,可做少量的数据操作,不需要把子模块所有功能带入,但是也不允许什么都不做
- 组装测试(集成/联合测试)
- 在单元测试的基础上,需要将所有的模块按照设计要求组装成为系统
- 一次性组装方式:对每个模块分别测试,然后全部组装到一起进行测试
- 增值式组装方式:边加入边测试
- 自顶向下增值方式:先进行主(根)模块,然后DFS
- 自底向上增值方式:一层一层往上,需要全部组装完才得到整个实体,但是无需考虑桩模块
- 混合增值式
- 确认测试
- 验证软件的有效性,功能特性是否满足用户所需
- 黑盒测试、软件配置复查、$\alpha$测试(开发环境或内部模拟环境)、$\beta$测试(单用户或多用户在实际情况下的测试)、验收测试、确认测试结果(符合或不符合)
- 系统测试
- 结合计算机硬件、外设、某些支持的软件等结合在一起测试
- 类型:功能测试、回归测试、可靠性测试、强度测试、性能测试、恢复测试、启动/关机测试、配置测试、安全性测试、可使用性测试、可支持性测试、安装测试、互连测试、兼容性测试、容量测试、文档测试
- 人工测试
- 一些人工的模拟技术和一些类似动态分析所使用的方法对程序分析
- 自动化测试
- 脚本调试
软件维护
类型
- 改正性维护:特定环境下所暴露出来的问题
- 适应性维护:对新环境的适应维护
- 完善性维护:加新功能
- 预防性维护
- 维护需要申请维护报告与记录
逆向工程
重构
程序修改步骤
- 分析和理解程序
- 实施修改
- 重新验证程序
副作用
- 修改代码副作用
- 修改数据副作用
- 文档副作用
重新验证程序
- 静态确认
- 确认测试
- 维护后的验收
软件的维护性
- 特性:易分析性、易变更性、稳定性、测试性、维护性符合性
- 提高软件维护性方法
- 使用提高软件维护性的开发技术和工具
- 模块化
- 结构化程序设计
- 实施开发阶段产品的维护性审查
- 改进文档
- 使用提高软件维护性的开发技术和工具