学不完了!!!
概述
什么是软件危机?
- 落后的软件生产方式无法满足迅速增长的计算机软件需求,从而导致软件开发与维护过程中出现的一系列严重问题的现象。
软件危机的形成
- 软件生产规模增大,复杂度增大
- 软件生产效率低
- 软硬件供需失衡
软件危机的具体体现包括哪些?
- 软件开发进度难以预测
- 软件开发成本难以控制
- 用户对产品功能难以满足
- 软件产品质量难以保证
- 软件产品难以维护
- 软件缺少适当的文档资料
什么是软件工程?
- 软件工程是指计算机软件开发和维护的一门工程学科。采用工程的概念、原理、技术、和方法来开发和维护软件,把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来,经济地开发出高质量的软件并有效地维护它。
软件生命周期
- 软件定义:
- 问题定义与可行性研究:确定总目标,可行性,应采取的策略和要实现的功能,估算成本,制定进度计划
- 需求分析:弄清用户的全部需求,编写需求规格说明书和初步用户手册,提交评审
- 软件开发:
- 软件设计
- 程序编码
- 单元测试、综合测试
- 运行维护:
软件过程模型
-
边做边改模型(Build and Fix):适合小型项目
-
瀑布模型
- 规定了各项软件工程活动自上而下,相互衔接的固定顺序,线性过程
- 强调文档的作用,要求每阶段都仔细验证。
- 缺点:
- 各阶段划分固定,缺乏灵活性,阶段之间产生大量文档,极大地增加了工作量
- 用户到过程末期才能见到开发成果,增加开发风险
- 早期的错误可能要到开发后期的测试阶段才能发现,带来严重后果
- 适用于需求比较明确的场合
-
快速原型模型
- 又称演进模型,由于在项目开发的初始阶段人们对软件的需求认识常常不够,所以可以先快速开发一个满足初始构想的模型,探索可行性,弄清软件需求,然后在此基础上获得较为满意的软件产品。
- 优点:可以增量式地开发出需求规格说明,开发出一部分,向用户展示一部分,用户能够及早看到部分软件,及早发现问题。
- 灵活性强,适合于软件需求不明确,设计方案有一定风险的软件项目
-
形式化系统开发模型
-
面向复用的开发模型
-
增量模型
- 把软件产品作为一系列的增量构件来设计、实现和确认。每个构件由多个相互作用的模块构成。
- 优点:
- 客户在早期就能看到最核心的功能
- 项目失败的风险较低
- 缺点
- 如果需求不像早期思考的那样稳定或没有对用户的变更需求进行规划,那么初始增量可能造成后来增量的不稳定,一些增量可能需要重新发布
-
螺旋模型
- 瀑布模型和快速原型模型的结合,加入了两种模型均忽略的风险分析。螺旋模型将开发过程分为几个螺旋周期,每个螺旋周期大致和瀑布模型相符合。
- 强调风险分析
- 适用于庞大、复杂、高风险的系统
-
喷泉模型
- 适用于面向对象的开发,具有迭代性和无间隙性
- 各阶段相互重叠
-
智能模型
- 把瀑布模型和专家系统综合在一起
-
快速应用开发模型
- 强调采用极短的开发周期,如果需求非常清楚并且项目范围边界也很清晰,适合采用这种模型
- 不同模块可以在同一时间并行开发
-
Rational统一开发过程(RUP)
- 用例驱动的、以体系结构为核心的、迭代的增量的过程
- 将一个大型项目分解为可连续应用瀑布模型的几个小部分
可行性研究
四个方面可行性研究
- 经济可行性:包括成本和效益
- 技术可行性:技术现状、技术潜力、生产率和风险处理、软件质量
- 社会可行性:市场、政策、知识产权、道德
- 操作可行性:项目的运行方式是否行得通、现有管理制度、人员素质和操作方式是否可行
UML中的关系
-
常见的关系有:依赖、关联、泛化、实现
-
依赖:--------->
- 一个事物发生变化会影响到另一个事物
- 源事物依赖于目标事物
-
关联:―――――――――
- 两个或多个类的实例之间的连接关系(如老师和学生)
- 包括普通关联、限定关联、关联类、聚合
-
泛化:――――――――(空心三角)
- 普通泛化(类似继承
- 受限泛化(泛化具有约束条件
-
实现:--------(空心三角)
- 泛化关系和依赖关系的结合,通常在以下两种情况出现实现关系:
- 接口和实现它们的类或构件之间
- 用例和实现它们的协作之间
UML中的图
- 外部视图:从参与者的角度观察和描述系统
- 用例图、活动图、顺序图
- 内部视图:从开发者的角度描述系统设计和实现以提供服务
- 类图、对象图(类的实例)、通信图、状态机图、构件图、包图、部署图
需求分析
- 需求的定义:一是用户所要求的系统应具有的外部行为,二是开发者所要求的系统应具有的内部特性。需求一定需要文档化。
需求层次
- 业务需求:为什么开发系统,系统的业务范围、业务对象、客户、价值等
- 用户需求:用户对系统的目标要求,只涉及系统的外部可见行为
- 功能需求和非功能需求:
- 功能需求:开发者应提供的软件功能或服务
- 非功能需求:对功能需求的补充,包括对系统的各种限制和用户对系统的质量要求
- 系统需求:来自于系统分析和结构设计,如行业业务规则
软件需求工程的过程
- 获取当前系统的具体物理模型
- 抽象出当前系统的逻辑模型
- 建立目标系统的逻辑模型
- 转换为目标系统的物理模型
- 2和3是需求工程要完成的工作
- 迭代的过程:
- 需求获取->需求分析建模->编写需求规格说明->需求有效性验证
需求获取的方法
- 基于数据流的结构化分析法
- 基于用例的建模方法
需求分析
- 传统的分析建模方法(基于数据流的结构化分析法)
- 模型结构:
- 实体关系图(ER图),用于数据建模
- 数据流图,用于功能建模
- 状态迁移图,用于行为建模
- 数据字典,与数据流图配合,清楚地表达数据处理的要求
- 模型结构:
- 面向对象的分析建模方法
- Booch方法
- Rumbaugh方法
- UML的OOA方法
需求规格说明
- 目的:分析需求草稿和模型,解决其中存在的二义性和不一致性
- SRS编制原则:
- 功能与现实分离(描述要做什么而非怎样实现)
- 使用面向处理的规格说明语言
- 如果被开发软件是一个大系统的子系统或一个元素,则整个大系统也在规格说明的描述之中
- 规格说明必须包括系统运行的环境
- SRS必须是一个认识的模型(用户能理解的)
- 必须是可操作的
- 必须容许不完备性并允许扩充
- 必须是局部化和松散耦合的
- SRS质量要求:
- 完整性
- 无歧义性
- 一致性
- 可验证性
- 可修改性
- 可追踪性
软件设计
软件设计的任务
- 基于需求分析的结果建立各种设计模型,给出问题解决的方案
- 从工程管理的角度,软件设计分为概要设计和详细设计阶段
- 从技术的角度,分为
- 传统的结构化方法:(概要)体系结构设计、数据设计、接口设计、(详细)过程设计
- 面向对象方法:(概要)体系结构设计、类设计/数据设计、接口设计、(详细)构件级设计
良好的设计原则
- 分而治之和模块化
- 模块独立
- 高内聚、低耦合
- 提高抽象层次
- 复用性设计
传统的面向过程的设计方法
- 又称结构化设计方法,与需求分析阶段的结构化分析方法相衔接
- 数据流图->接口设计、体系结构设计
- 实体关系图,数据字典->数据设计
- 状态迁移图->过程设计
- 结构图:描绘软件结构的图形工具,图中一个方框代表一个模块,框内注明模块的名字或主要功能;方框之间的箭头(或直线)表示模块的调用关系。
- 数据流分为变换型数据流和事物型数据流两种。
- 启发规则:深度、宽度、扇入、扇出都应适当。
- 深度表示软件结构中控制的层数,它往往能粗略地标志一个系统的大小和复杂程度
- 宽度是软件结构内同一个层次上的模块总数的最大值
- 一个模块的扇入表明有多少个上级模块直接调用它
- 扇出是一个模块直接控制(调用)的模块数目,扇出过大意味着模块过分复杂
面向对象的系统设计
- 主要活动是进行子系统分解
结构化程序设计的工具
- 程序流程图,N-S图,PAD图,判定表(多重嵌套的条件选择适用),PDL(伪码)
软件设计说明SDD
数据库设计说明DBDD
接口设计说明IDD
体系结构
软件体系结构定义
- 是具有一定形式的结构化元素,即构件的集合。包括处理构件、数据构件、连接构件。
软件构件
- 是一种组装单元,它具有规范的接口规格说明和显示的语境依赖。软件构件可以被独立部署,并由第三方独立地组装。
软件体系结构的结构风格
-
数据流风格
- 当输入数据经过一系列的计算和操作构件的变换形成输出数据时可以应用这种风格。
-
调用-返回风格
- 主程序/子程序体系结构:树状,自顶向下,逐步分解
- 面向对象结构:系统的构件封装了数据和应用到数据上的操作,构件间通过消息传递进行通信与合作。
- 层次结构:整个系统被组织成一个层次结构,每一层为上层提供服务,并作为下一层的客户。
-
仓库风格
- 数据仓库位于体系结构的中心,其他构件会经常访问该数据仓库,并对仓库中的数据进行增删改查。(数据库系统、黑板系统、超文本系统)
体系结构的控制模型
-
集中控制:一个子系统被指定作为系统控制器来负责管理其他系统的执行
- 调用-返回模型:自上而下的子过程模型,顺序执行
- 管理者模型:并发执行
-
事件驱动控制:通过外部产生的事件来驱动系统
- 广播模型:事件广播到所有子系统,任何能处理该事件的子系统都会相应
- 中断驱动模型:专用于实时系统。由中断处理器对来自外部的中断进行检测,并在其他组件中处理中断。
体系结构的模块分解
- 将子系统分解为模块,可供分解的模块有:
- 数据流模型:系统被分解为一些功能模块,这些功能模块接收输入数据并转换他们,有时还输出数据
- 面向对象模型:将系统分解为一组互相通信的对象,这些对象都有良好定义的接口。
特定领域的软件体系结构
- 类属模型
- 参考模型
分布式系统结构
-
分布式计算模型的优点:
- 资源共享
- 经济性
- 性能与可扩展性
- 固有分布性
- 健壮性
-
多处理器体系结构
- 多进程并行
- 适用于大型实时系统
-
客户机/服务器体系结构
- 两层C/S:
- 主要组成:
- 一组为其他子系统提供服务的服务器
- 一组向服务器请求服务的客户机
- 连接客户机与服务器的网络
- 逻辑上通常将应用系统划分为三层:
- 数据管理层
- 应用逻辑层
- 表示层
- 瘦客户机:1和2都在服务器上,客户机只负责3
- 胖客户机:只有1在服务器上,客户机负责2和3
- 主要组成:
- 三层C/S:
- 数据库服务器:数据管理层
- 应用服务器:应用逻辑层
- 用户:表示层
- 浏览器/服务器(B/S)就是三层应用结构的一种实现方式
- 两层C/S:
-
分布式对象体系结构
- 服务的提供者是被称为“对象(Object)”的系统构件
- 每个对象在逻辑上是平等的,它们可以互相为对方提供所需的服务
- 提供服务的对象就是服务器,而提出服务请求的对象就是客户
- 为了能够提供服务,每个对象都有一个服务接口
- 对象可能分布在网络的各个结点上而不是集中在一台硬件服务器上。为了将分散的对象提供的服务串起来,一种被称为“软件总线”的中间件起了关键的作用,如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FzpNiQ9o-1648540033024)(./%E5%88%86%E5%B8%83%E5%BC%8F%E7%BB%93%E6%9E%84.png)] - 当前主流的分布式对象技术规范:
- CORBA
- .NET
- J2EE
-
代理
- 构建带有隔离组件的分布式软件系统,该软件通过远程服务调用进行交互。代理者负责协调通信。
- 以ORB(Object Request Broker)为中心的分布式应用体系结构,以实现互操作性为主要目的
- 在ORB上有四个接口,如图
- 对象接口:定义加入ORB的系统服务
- 公共设施:水平级的服务,定义应用程序级服务
- 领域接口:面向特定领域
- 应用接口:面向指定的现实世界应用
-
聚合和联邦体系
- 企业内部部署大规模分布式业务系统:相互之间多个系统集成起来以实现一种所需的解决方案
- 聚合
- 多个相同或相容的点连接起来
- 联邦
- 一组独立开发和部署的自治系统,互相协同以向用户提供更广泛的功能
设计模式
- 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结
- 如单例模式:
- 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
- 如工厂模式:
- 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。
- 使用设计模式的目的:为了代码可重用性、易理解性、保证代码可靠性。设计模式分为三种类型,共 23 种。
- 创建型设计模式:描述怎样创建一个对象
- 单件模式、抽象工厂模式、生成器模式、工厂方法模式、原型模式。
- 结构型设计模式:描述类和对象之间怎样组织起来形成大的结构,从而实现新的功能
- 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
- 行为型设计模式:主要解决算法和对象之间责任的分配的问题。
- 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式)、访问者模式。
软件实现
程序设计方法
-
结构化程序设计
- 以自顶向下、逐步求精的方式编写
- 使用基本控制结构(赋值、循环、选择)构造程序
-
面向对象的程序设计方法
- 封装
- 泛化
- 多态
- 协同:一组对象通过它们之间的协作完成任务
- 复用
-
极限编程
- 适合规模小、进度紧、需求变化大、质量要求严的项目
编程风格
- 源程序文档化:命名、注释、程序段组织
- 数据说明规范化
- 程序代码结构化
- 输入/输出风格可视化
程序复杂性度量
-
代码行度量法:没有很好地区分每行代码的复杂度
-
McCabe度量法
- 度量值又称环路复杂度,基于一个程序模块的控制流图中环路的个数
- V(G)=m-n+2p
- m:边数
- n:结点数
- p:强连通图个数
-
Halstead度量法:按程序中的操作符个数和操作数的个数来衡量程序模型的复杂程度
- n1:程序中不同运算符(包括保留字)的个数
- n2:程序中不同运算对象的个数
- H=n1*log(n1)+n2*log(n2)
软件测试
软件测试的目的
- 以最少的时间和人力系统地找出软件中潜在的各种错误和缺陷。如果成功实施了测试,就能发现软件的错误。
- 证明软件的功能和性能与需求说明相符合。
软件错误
- 按错误的影响和后果分类:微小错误、一般错误、较严重错误、严重错误、非常严重的错误、最严重的错误
- 按错误的性质和范围分类:功能错误、系统错误、加工错误、数据错误、代码错误
- 按软件生存周期阶段分类:需求错误、功能与性能错误、程序结构错误、数据错误、实现和编码错误、集成错误、系统结构错误、测试定义与测试执行错误
人工测试
- 桌面检查:程序员个人模拟计算机阅读程序,发现代码错误
- 代码审查:以小组为单位阅读代码,应用一系列规程和缺陷检查技术,检查实际的产品。
- 走查:审查者对程序进行模拟,展示程序如何处理数据。主要针对用例场景和程序逻辑。
软件测试分类
- 按开发阶段划分:
-
软件需求分析阶段的测试活动
-
软件设计阶段的测试活动
-
单元测试:针对软件设计的最小单位程序模块,以模块详细设计为依据,对输入、输出和处理进行测试,用以发现各模块可能存在的错误。
- 驱动模块:被测模块的控制程序
- 桩模块:代替被测模块调用的子模块
- 自顶向下
- 自底向上
- 孤立测试
- 综合测试
-
集成测试:在单元测试通过的基础上,以概要设计为依据,按照模块之间的调用关系将模块组装起来进行的测试,用以发现功能(主要在接口上)的错误。
- 基于分解的集成方式
- 基于层次的集成
- 基于路径的集成
-
系统测试:对象是整个软件系统,以需求规格说明为依据,检查软件的功能、性能、接口及其可靠性是否与用户需求分析说明书的要求一致。
- 功能测试
- 协议一致性测试
- 性能测试
- 压力测试
- 容量测试
- 安全性测试
- 恢复性测试
- 备份测试
- GUI测试
- ……
-
验收测试:同上,是系统测试的一个子集。是以客户为主的测试,由客户参加设计测试用例。
- α测试:由一个用户在开发环境下进行的测试,也可以是公司内部的用户在模拟实际操作环境下进行的测试。开发者坐在用户旁边,随时记下错误情况和使用问题
- β测试:由软件的多个用户在一个或多个用户的实际使用环境下进行的测试。这些用户使用该产品并返回有关错误给开发者。
- 只有当α测试达到一定的可靠程度时才开始β测试
-
运行和维护阶段的测试活动
-
回归测试:在软件变更之后对软件重新进行的测试。目的是检验对软件进行的修改是否正确,其正确性包括:
- 修改达到了预定目的
- 不影响软件其他功能的正确性
-
软件测试用例设计方法
黑盒测试
- 又称功能测试。根据产品的外部功能来规划测试,从用户观点出发。把测试对象看做一个黑盒子,完全不考虑程序内部的逻辑结构和内部特性,只依据程序的需求规格说明,检查程序的功能是否符合它的功能说明。
- 黑盒测试用例设计方法
-
等价类划分:把所有可能的输入数据划分成若干子集,然后从每一个等价类中选取少数有代表性的数据作为测试用例
- 有效等价类:合理的、有意义的输入数据构成的集合
- 无效等价类:不合理的、无意义的输入数据,利用这一类测试用例检查程序中功能和性能的实现是否有不符合规格的地方
-
边界值分析:挑选那些位于边界附近的值作为测试用例
-
判定表法:适合描述在多个逻辑条件取值的组合所构成的复杂情况下,分别要执行哪些不同的动作
-
因果图法:既考虑输入条件的组合关系,又考虑输出条件对输入条件的依赖关系
-
白盒测试
- 又称结构测试。基于产品的内部结构来规划测试,检查程序内部操作是否按规定运行,各部分代码是否被充分覆盖。
- 白盒测试用例设计方法
-
逻辑覆盖
- 语句覆盖:每一句至少执行一次
- 判定覆盖/分支覆盖:每个判定的取真和取假分支至少执行一次
- 条件覆盖:程序中每个判定的每个条件的可能取值至少被取得一次。满足条件覆盖的不一定满足判定覆盖
- 条件/判定覆盖:每个条件的所有可能至少取得一次,同时,每个判定语句的可能分支也至少取得一次
- 条件组合覆盖:每个判定的所有可能的条件取值组合至少执行一次
- 路径覆盖:执行程序中所有可能的路径
-
判定和循环结构测试
- 判定结构
- 嵌套性分支
- 连锁性分支
- 循环结构
- 单重循环
- 嵌套循环
- 连锁循环
- 非结构循环
- 判定结构
-
基本路径测试
- 基本路径法是在程序控制流图的基础上,通过分析控制构造的环路复杂性,导出基本可执行的路径集合,从而设计测试用例的方法。
- 复杂性计算:区域数,或判定节点数+1,或边数-节点数+2。
-
软件维护
软件维护的类型
- 软件维护是指软件系统交付使用以后,为了改正错误或满足新的需求而修改软件的过程。按照不同的维护目的,维护工作可分成4类:
-
完善性维护(Perfective Maintenance)
- 定义:扩充软件功能、增强软件性能、提高软件运行效率和可维护性而进行的维护活动。
- 策略:可以使用功能强、使用方便的工具,或采用原型化方法开发的等。
-
适应性维护(Adaptive Maintenance)
- 定义:为了适应计算机的飞速发展,使软件适应外部新的硬件和软件环境或者数据环境(数据库、数据格式、数据输入/输出方式、数据存储介质)发生的变化,而进行修改软件的过程。
- 策略:对可能变化的因素进行配置管理,将因环境变化而必须修改的部分局部化,即局限于某些程序模块等。
-
改正性维护(Corrective Maintenance)
- 对在测试阶段未能发现的,在软件投入使用后才逐渐暴露出来的错误的测试、诊断、定位、纠错,以及验证、修改的回归测试过程称为纠错性维护。
- 策略:开发过程中采用新技术,利用应用软件包,提高系统结构化程度,进行周期性维护审查等。
-
预防性维护(Preventive Maintenance)
- 定义:为了提高软件的可靠性和易维护性,采用先进的软件工程方法对需要维护的软件或软件中的某一部分重新进行设计、编制和测试,为以后进一步维护和运行打好基础。也就是软件开发组织选择在最近的将来可能变更的程序,做好变更它们的准备。
- 策略:采用提前实现、软件重用等技术。
-