软件工程概述
软件危机
介绍
- 软件危机包含两个问题:如何开发软件以应对日益增长的需求,以及如何维护数量不断增长的已有软件。
- 软件危机表现:
- 对软件开发成本和进度估计不明确
- 用户对已完成的软件系统市场不满意
- 软件质量靠不住
- 不可维护
- 软件通常没有合适的文档材料
- 软件成本在计算机系统的成本中所占的比例提升
- 软件开发生产率提高速度过慢
原因
- 软件开发不同于硬件,是逻辑部件,缺乏可见性,所以开发进展较难衡量
- 软件规模庞大,难以组织分工合作
消除途径
- 软件是程序,数据及相关文档的完整集合。(不仅仅是程序)
- 程序是能够完成预定功能和性能的可执行的指令序列
- 数据是使程序能够适当地处理信息的数据结构
- 文档是开发、使用、和维护程序所需要的图文资料
软件工程
软件工程是知道计算机软件开发和维护的一门工程学科
介绍
本质特征:
- 软件工程关注余大型程序的构造
- 软件工程的核心课题是控制复杂性:把大问题分解成几个小的问题
- 软件经常变化
- 软件开发效率非常重要
- 和谐合作是软件开发的关键
- 软件必须有效的支持他的用户
- 通常由具有一种文化背景的人体具有另一种文化背景的人创造产品
基本原理
- 用分阶段的生命周期计划严格管理
- 坚持进行阶段评审
- 实施严格产品管控
- 采用现代化程序设计技术
- 结果应能清楚地审查
- 开发人员小组应少而精
- 承认不断改进软件工程实践的重要性
方法学
- 软件生命周期全过程中使用的一整套技术方法的集合称为方法学
- 软件工程方法学包含三个要素:方法工具和过程。
- 传统方法学
- 又名生命周期方法学或结构化范型
- 采用结构化技术(结构化分析结构化设计结构化实现)
- 把软件开发的生命周期划分为若干个阶段,然后顺序的完成每个阶段。
- 维护较为困难
- 面向对象方法学=对象+类+继承+用消息通信
- 软件规模较大时,使用传统方法学往往不成功
- 数据和行为同等重要,以数据为主线,把数据和对数据的操作紧密的结合起来。
- 主要有以下四个要点:
- 把对象作为融合了数据以及在数据上操作行为的统一软件构件
- 把所有对象都划分成类
- 按照父类与子类的关系把若干个相关类组成一个层次结构的系统
- 对象之间仅能通过发送消息互相联系
软件生命周期
- 软件定义:问题定义,可行性研究,需求分析
- 软件开发:总体设计,详细设计,编码和单元测试,综合测试
- 软件维护
软件过程
瀑布模型
- 阶段间具有顺序性和依赖性
- 推迟实现的观点
- 质量保证的观点
- 每个阶段都必须完成规定的文档
- 每个阶段结束前都必须对所完成的文档进行评审
- 反馈环
- 文档驱动
快速模型原型
- 快速建立起可以在计算机上运行的程序,它所完成的功能往往是最终产品的一个子集。通过用户提出的修改意见来改进系统
增量模型
- 将系统分解为一系列的增量构件来设计编码和测试
- 分解必须遵守的约束:当把新的构件添加到系统中时,所形成的产品必须是可测试的
螺旋模型
- 风险驱动
喷泉模型
- 主要用于面向对象开发
Rational统一过程
- Rational Unified Process(RUP)
- 最佳实践
- 迭代式开发
- 管理需求
- 使用基于构建的体系结构
- 可视化建模
- 验证软件质量
- 控制软件变更
- RUP软件开发生命周期
- 二维的生命周期模型
- 纵轴核心工作流,横轴时间
敏捷过程与极限编程
- 敏捷过程
- 四个简单的价值观:
- 个体和交互胜过过程和工具
- 可以工作的软件胜过面面俱到的文档
- 客户合作胜过合同谈判
- 相应变化胜过遵守计划
- 四个简单的价值观:
- 极限过程
- 属于敏捷过程
- 极限编程的有效实践
- 极限编程的整体开发过程极限编程的迭代过程
微软过程
可行性研究
可行性研究的任务
- 技术可行性
- 经济可行性
- 操作可行性
可行性研究过程
- 复查系统规模和目标
- 研究目前正在使用的系统
- 导出新系统的高层逻辑模型:数据流图和数据字典
- 进一步定义问题
- 导出和评价供选择的解法
- 推荐行动方针
- 草拟开发计划
- 书写文档提交审查
系统流程图
概括的描述物理系统的传统工具
- 符 :基本符 ,系统符
- 例子
- 分层:先用高层次整体概括再具体细化每个功能
数据流图(DFD)用于建立功能模型
- 符 :四种基本符 :正方形,表示数据的源或终点;圆角矩形,表示数据的变换处理;开口矩形,表示数据的存储;箭头,表示数据的流动方向。
- 附加符 的含义。”* + 抑或”
- 通常忽略出错处理和内务处理,只考虑做什么而不考虑怎样做。
数据字典
数据字典内容:
- 数据流
- 数据流分量
- 数据存储
- 处理
需求分析
结构化分析方法准则:必须理解并描述问题的信息域,根据这条准则建立数据模型
必须定义软件应该完成的功能,根据这条准则建立功能模型
必须描述作为外部事件结果的软件行为,根据这条准则建立行为模型
必须对描述信息,功能,行为的模型进行分解。用层次的方式展示细节
需求分析任务
确定系统的综合要求
- 功能需求
- 性能需求
- 可靠性和可用性需求
- 出错处理需求
- 接口需求
- 约束
- 逆向需求
- 将来可能提出的需求
分析系统的数据要求
导出系统的逻辑模型
修正系统的开发计划
分析建模与规格说明
分析建模
- 模型:为了理解事物而对事物做出的一种抽象,是对事物的一种无奇异的书面描述,通常由一组图形符 和组织这些符 的规则组成
需求规格说明
- 除了创建分析模型外,还应该写出软件的需求规格说明书
实体–联系图(用于建立数据模型)
- 描述了从用户角度看到的数据,反映了用户的现实环境,反而与在软件中的实现无关
- 包含三种相互关联的消息:数据对象、数据对象的属性、数据对象彼此之间相互连接的关系
数据规范化
- 第一范式
- 第二范式
- 第三范式
状态转换图(用于建立行为模型)
其他图型工具
- 层次方框图
- Warnier图
- IPO图
验证软件需求
从哪些方面验证
- 一致性
- 完整性
- 现实性
- 有效性
验证软件需求的方法
- 验证需求的一致性
- 验证需求的现实性
- 验证需求的完整性和有效性
用于需求分析的软件工具
形式化说明技术
总体设计
设计过程
总体设计通常包含两个阶段:系统设计阶段确定系统的具体实现方案和结构设计阶段确定软件结构。
典型的总体设计过程包括以下九个步骤:
- 设想供选择的方案
- 选择合理方案
- 推荐最佳方案
- 功能分解
- 设计软件结构
- 设计数据库
- 制定测试计划
- 书写文档
- 系统说明
- 用户手册
- 测试计划
- 详细的实现计划
- 数据库测试结果
- 审查和复审
设计原理
模块化
模块是由边界元素限定的相邻程序元素,有一个总体标识符代表他。如C,C++中的{……}
但是,随着模块的细化,设计模块之间的接口的成本会大大增加,总成本也会上升。
抽象
把相似的方面集中和概括起来,暂时忽略他们之间的差异。
逐步求精
为了集中主要精力解决主要问题而尽量推迟对问题细节的考虑
抽象与求精是一对互补的概念,抽象是的设计者能够说明过程和数据同时却暂时忽略底层细节。事实上,可以吧抽象看作是一种通过忽略多于细节的同时强调有关的细节,从而实现逐步求精的方法。求精则帮助设计者在设计过程中逐步揭示出底层细节。
信息隐藏和局部化
信息隐藏:模块内包含的信息对于不需要这些信息的模块来说是不能访问的
局部化:把一些关系密切的软件元素物理地放的比较靠近
模块独立
开发具有独立功能的而且和其他模块之间没有过多相互作用的模块就可以做到模块独立。
耦合
对一个软件结构内各个模块之间的互联程度的度量
追求尽可能松散的耦合系统
- 耦合强度
- 完全独立:各个模块之间完全独立,没有任何连接
- 数据耦合(低耦合):模块之间通过参数交换消息,而且交换的信息仅仅是数据
- 控制耦合(中等程度耦合):模块之间的传递控制信息,往往是多余的,模块适当分解后可用数据耦合替换。
- 特征耦合:当把整个数据结构(如结构体,对象)作为参数传递进一个模块而该模块仅需要一部分数据元素时,就出现了特征耦合。
- 公共环境耦合:两个或多个模块通过一个公共数据环境相互作用时,他们之间的耦合称为公共环境耦合。
- 内容耦合(最高程度的耦合):
- 一个模块访问另一个模块的内部数据
- 一个模块不通过正常入口而转到另一个模块的内部
- 两个模块有一部分代码重叠
- 一个模块有多个入口
尽量使用数据耦合,少用控制耦合和特征耦合,限制公共环境耦合范围,完全不用内容耦合
内聚
标志着一个模块内各个元素之间彼此结合的紧密程度,理想内聚的模块只做一件事情
- 低内聚:
- 偶然内聚
- 逻辑内聚
- 时间内聚
- 中内聚:
- 过程内聚:一个模块内的处理元素是相关的,而且必须以特定的次序执行,则称为过程内聚,通常通过流程图划分模块时得到过程内聚模块。
- 通信内聚:模块中所有元素都使用同一个输入数据和产生同一个输出数据,则称为通信内聚
- 高内聚:
- 顺序内聚:一个模块内的处理元素和同一个功能密切相关而且这些处理必须顺序执行,通常通过数据流图划分模块时得到的是顺序内聚模块。
- 功能内聚:模块内所有处理元素属于一个整体,完成单一的功能。最高程度的内聚。
启发规则
- 改进软件结构提高模块独立性
- 模块规模应该适中
- 深度宽度扇出扇入都应适当
- 扇出:直接控制的下级模块的数目
- 扇入:被上级模块调用的数目
- 好的系统顶层扇出高,中层扇出少,底层扇入高,平均扇出3-4
- 模块的作用域在控制域内。
- 力争降低模块接口的复杂度
- 设计单入单出的模块
- 模块的功能应该可以预测
描绘软件结构的图形工具
层次图和HIPO图
层次图
形式上与3.7层次方框图相同,但是内容上完全不同:层次图中的每个矩形代表一个模块,方框间的连线表示 调用关系 而不是层次方框图的 组成关系 。
HIPO图
在层次图里除了最顶层的方框外每个方框都加了编 。
结构图
面向数据流的设计方法
概念
变换流
事务流
- 以事物为中心
- 事务中心
- 接收输入数据
- 分析每个事物以确定他的类型
- 根据事物类型选取一条活动通路
设计过程
详细设计
结构程序设计
- 经典的结构程序设计
- 扩展的结构程序设计(允许使用case,do——until)
- 修正的结构程序设计(允许使用case,do——until,break)
人机界面设计
设计问题
- 系统响应时间
- 用户帮助设施
- 出错信息处理
- 命令交互
设计过程
人机界面设计指南
- 一般交互指南
- 信息显示指南
- 数据输入指南
过程设计工具
程序流程图
又称程序框图,缺点:
- 本质上不是逐步求精的好工具,诱使程序员过早的考虑程序的控制流程,而不是考虑程序的全局结构
- 程序流程图中的箭头表示控制流,因此,程序员不受任何约束,可以不顾结构程序设计的精神而随意转移控制
- 程序流程图不易表示数据结构
盒图(N-S图)
特点:
- 功能域明确,可以从盒图上一眼就看出来
- 不可能任意转移控制
- 很容易确定局部和全局的数据作用域
- 很容易表现嵌套关系,也可以表示模块的层次结构
PAD(problem analysis diagram)图
优点:
- 使用结构化控制结构的PAD符 设计出来的程序必然是结构化的
- 描绘的程序结构非常清晰
- 程序逻辑通俗易懂
- 可将PAD图自动转化成高级语言源程序
- 即可描述程序逻辑,也可表述数据结构
- 支持自顶向下,逐步求精方法的使用(通过def符 增加细节)
判定表
用于清晰地表示复杂的条件组合和应做的动作之间的对应关系
判定树
过程设计语言PDL(伪码)
面向数据结构的设计方法
最终目标是得出对程序处理过程的描述。这种方法最适合于在详细设计阶段使用,也就是在完成了软件结构设计之后可以使用面向数据结构的方法来设计每个模块的处理过程。Jackson方法和Warnier方法。
Jackson图
- 顺序结构:由一个或多个数据元素组成,每个元素按照确定顺序出现一次。
- 选择结构:包含两个或多个数据元素,每次使用这个数据时按照一定顺序从这些数据元素中选择一个。
- 重复结构:根据使用时的条件由一个数据元素出现零次或多次构成。
改进的Jackson图
Jackson方法(难点)
步骤:
- 分析并确定输入数据和输出数据的逻辑结构
- 找出输入数据和输出数据中有对应关系的数据单元
- 通过以下三条规则从描述数据结构的Jackson图导出描绘程序结构的Jackson图:
- 为每对有对应关系的数据单元,按照他们在数据结构中的层次在程序结构图相应层次画一个处理框。
- 根据输入数据结构中剩余的每个数据单元所处的层次,在程序结构图中的相应层次分别为他们画上处理框
- 根据输出数据结构中剩余的每个数据单元所处的层次,在程序结构图中的相应层次分别为他们画上处理框
- 列出所有操作和条件,并把它们分配到程序结构图相应的位置
- 用伪码表示程序
程序复杂度的定量度量
McCabe方法
流图
根据程序控制流的复杂度定量度量程序的复杂度,这样的度量结果称为程序的环形复杂度
为突出表现程序的控制流,使用退化的程序流程图即流图。
计算环形复杂度的方法
- 流图中的线性无关区域数等于环形复杂度
- 流图G的环形复杂度V(G)=E-N+2,E是流图中的边的条数,N是节点数。
- 流图G的环形复杂度V(G)=P+1,P是流图中判定节点的个数。
通常V(G)<=10为宜
环形复杂度的用途
Halstead方法
根据程序中的运算符(包括关键字)和操作数的总数来度量程序的复杂度
总结
过程设计在数据设计、体系结构设计和接口设计完成之后进行,它的任务是设计解题的详细步骤,是详细设计阶段应完成的主要工作,有图形,语言,表格三类工具,三类工具各有所长。
实现(编码和测试)
编码
选择程序设计语言
编码风格
- 程序内部文档
- 数据说明
- 语句构造
- 输入输出
- 效率
- 程序运行时间
- 存储器效率
- 输入输出的效率
软件测试基础
软件测试的目标
软件测试的准则
- 所有测试都能追溯到用户需求
- 应该远在测试开始之前就制定测试计划
- 把Pareto原理应用到软件测试中(Pareto原理:二八准则)
- 应该从小规模的测试开始,并逐步进行大规模的测试
- 穷举测试是不可能的
- 为得到最佳的测试效果,应由独立的第三方从事测试工作
测试方法
- 黑盒测试(功能测试)和白盒测试(结构测试)
测试步骤
- 模块测试(单元测试)
- 子系统测试(着重测试模块的接口)
- 系统测试(集成测试):发现软件设计中的错误,也可能发现需求说明中的错误
- 验收测试(确认测试):发现需求说明书中的错误
- 平行测试::同时运行新系统和旧系统,以便比较新旧两个系统的处理结果。
测试阶段的信息流
单元测试
测试重点
- 模块接口
- 局部数据结构
- 重要的执行通路
- 出错处理通路
- 边界条件
代码审查
计算机测试(开发驱动软件和存根软件以供测试)
集成测试
自顶向下集成
深度优先,宽度优先策略把各个模块结合进软件结构:
步骤:
- 对主控模块进行测试,测试时用存根程序代替所有的直接附属于主控模块的模块
- 根据选定的结合策略(深度或者宽度优先),每次用一个实际模块代换一个存根程序
- 结合进一个模块的同时进行测试
- 为了保证加入模块没有引进新的错误,可能需要进行回归测试
优点: - 不需要测试驱动程序
- 能在测试初期实现并验证主要功能
- 能在早期发现上层模块中的接口错误
缺点: - 需要存根程序
- 底层关键模块中的错误发现较晚
- 早起不能够充分展开人力。
自底向上集成
不需要存根程序
步骤:
- 把低层模块组合成实现某个特定的软件子功能的族。
- 写一个驱动程序,协调测试数据的输入输出
- 对由模块组成的子功能族进行测试。
- 去掉驱动程序,沿软件结构自底向上移动,把子功能组集合组成更大的功能族。
优缺点与自顶向下集成相反
回归测试
确认测试
确认测试的范围
通常使用黑盒测试方法
软件配置复查
Alpha测试和Beta测试
- Alpha测试是由用户在开发者场所进行,并且在开发者对用户的指导下进行的。
- Beta测试有软件的最终用户在一个或多个用户场所进行测试。
白盒测试
逻辑覆盖
- 语句覆盖(每个语句至少执行一次)
- 判定覆盖(又叫分支覆盖,不仅每个语句执行一次,而且每个判定的每种可能结果都应该执行一次)
- 条件覆盖(不仅每个语句执行一次,判定表达式中的每个条件都取到各种可能的结果)
- 判定/条件覆盖(选取足够多的测试数据,使得判定表达式中的每个条件都取到各种可能的值,而且每个判定表达式也都取到各种可能的结果)
- 条件组合覆盖(使得每个判定表达式中条件的各种可能组合都至少出现一次。
- 点覆盖(通常和语句覆盖是一致的)
- 边覆盖(通常和判定覆盖是一致的)
- 路径覆盖(程序的每条路径都至少执行一次)
控制结构测试
基本路径测试
- 根据过程设计结果画出流图
- 计算流图的环形复杂度
- 确定线性独立路径的基本集合(独立路径:至少包含一条在定义该路径前不曾用过的边),集合的大小为环形复杂度
- 设计可执行基本集合中每条路径的测试用例
条件测试(检查程序模块中包含的逻辑条件)
循环测试(测试循环结构的有效性)
- 简单循环
- 嵌套循环
- 串接循环
黑盒测试技术
调试
结果:
- 找到了原因并把问题改正
- 没找到原因,假设一个原因,再次测试以验证
软件可靠性
基本概念
软件可靠性的定义
程序在给定的时间间隔内,按照规格说明书的规定成功运行的概率
软件可用性
程序在给定的时间点,按照规格说明书的规定,成功运行的概率
稳态可用性
估算平均无故障时间方法
- 符
- 基本假定
- 估算平均无故障时间
- 估计总错误数方法
- 植入错误法
- 分别测试法
维护(太累了不想写这个了)
软件维护的定义
面向对象方法学引论
面向对象方法学概述
面向对象方法学的要点
- 原则,尽可能模拟人类习惯的思维方式
面向对象方法学的优点
- 与人类的思维方式一致
- 稳定性好
- 可重用性好
- 教易开发大型软件
- 可维护性好
面向对象概念
对象
- 对象的形象表示
- 对象的定义
- 对象的特点
- 以数据为中心
- 对象是主动的
- 实现了数据封装
- 本质上具有并行性
- 模块独立性好
其他概念
- 类
- 实例
- 消息
- 方法
- 属性
- 封装
- 继承
- 多态
- 重载
面向对象建模
- 描述系统数据结构的对象模型
- 描述系统控制结构的动态模型
- 描述系统功能的功能模型
对象模型
表示静态的,结构化的系统的数据性质。
类图的基本符
类图描述类与类之间的静态关系。
定义类
定义属性
- 可见性:+(共有)-(私有)#(保护)
- 类型名表示该属性的数据类型
- 性质串明确了该属性的所有可能取值,也可用性质串说明属性的其他性质,如,{只读}
定义服务
表示关系的符
关联
- 普通关联
- 重数:0…1 0…* * 1+ 1…* 1…15 3
- 关联角色
- 限定关联(限定词通常放在关联关系的末端的一个小方框内)
- 关联类
聚集(聚合)
是关联的特例,表示类与类之间的关系是整体与部分的关系。
- 共享聚集
- 组合聚集
泛化(继承关系)
- 普通泛化
- 抽象类
- 具体类
- 受限泛化
- 多重继承:一个子类可以多次继承同一个基类
- 不相交继承:一个子类不能多次继承同一个基类,默认不相交
- 完全继承:父类的所有子类都已在类图中列举出来
- 不完全继承:父类的所有子类没有在在类图中完全列举出来
依赖和细化
- 依赖关系
- 细化关系
动态模型
规定了对象模型中的对象的合法变化序列
每个类的动态行为用一张状态图来描述,个各类的状态图通过共享事件合并起来,从而构成系统的动态模型。
功能模型
表示变化的系统的功能的性质,指明了系统应该做什么,更直接的反映了用户对目标系统的需求
通常,功能模型由数据流图组成
用例图
包含的模型元素有:系统,行为者,用例,用例之间的关系
- 用例具有以下特征:
- 用例代表某些用户可见的功能,实现一个具体的用户目标
- 用例总是被行为者启动,并向行为者提供可识别的值
- 用力必须是完整的
- 用例是个类
- 行为者:与系统交互的人或其他系统
- 用例之间的关系
- 扩展关系
- 使用关系
用例建模
- 寻找行为者
- 寻找用例
三种模型之间的关系
面向对象分析
分析工作包括三部分内容:理解、表达、验证
面向对象分析基本过程
三个子模型与五个层次
- 三个子模型:对象模型、动态模型、功能模型
- 五个层次
- 主题层:指导读者理解大型,复杂模型的一种机制。
- 类与对象层:
- 结构层
- 属性层
- 服务层
需求陈述
阐明做什么而不是怎么做。
建立对象模型
确定类与对象
找出候选的类与对象
筛选出正确的类与对象
确定关联
初步确定关联
筛选
进一步完善
划分主题
确定属性
识别继承关系
反复修改
建立动态模型
- 编写脚本
- 从脚本中提取事件
- 排列事件发生的次序
编写脚本
设想用户界面
画事件跟踪图
画状态图
并不是任何类都需要一张状态图描述其行为
审查动态模型
建立功能模型
- 通常在建立对象模型和动态模型后再建立功能模型
- 由一组数据流图组成
画出基本系统模型图
画出功能级数据流图
定义服务
- 常规行为
- 从事件导出的操作
- 与数据流图中处理框对应的操作
- 利用继承减少冗余操作
面向对象设计
面向对象实现
软件项目管理
估算软件规模
代码行技术
功能点技术
信息域特性
- 输入项数:用户向软件输入的项数。不同于查询
- 输出项数:软件向用户输出的项数。 表内的数据项不单独计数
- 查询数:
- 主文件数:
- 外部接口数:
进度计划
估算开发时间
甘特图
估算工程进度
关键路径
机动时间
人员组织
质量保证
软件配置管理
能力成熟度模型
告一段落!!
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!