概述
软件过程
生存周期
问题定义及可行性分析
确定软件开发目标,范围等,确定可行性
项目计划
制定初步开发计划
需求分析
解决“做什么”的问题
过程:
-
问题识别
从系统的角度来理解软件并评审软件范围是否恰当
确定对目标系统的综合要求,即软件的需求
提出这些需求实现条件,以及需求应达到的标准
-
分析与综合:从信息流和信息结构出发,细化所有软件功能,找出系统各元素之间的联系、接口特性和设计上的约束,分析它们是否满足功能要求,是否合理。给出目标系统的详细逻辑模型。
常用分析方法:
-
面向数据流的结构化分析方法
结构化分析方法是面向数据流的需求分析方法,过程是对系统信息进行分析,抽取其本质要素,创建描述数据和行为的模型。
-
自顶向下,逐步分解
-
抽象模型的概念
-
记录数据传递、变换
主要工具:
-
数据流图
在多层数据流图中,顶层流图仅包含一个加工,它代表被开发系统。底层流图是指其加工不需再做分解的数据流图。中间层流图则表示对其上层父图的细化。它的每一加工可能继续细化,形成子图。
-
数据字典
分析模型中出现的所有名字的一个集合,并包括有关命名实体的描述
-
结构化英语
-
判定表与判定树
-
-
面向对象分析方法
-
-
编制文档
-
需求分析评审
软件设计
-
概要设计
把各项需求转换成软件的体系结构
-
制定规范
-
系统结构的总体设计
-
确定每个模块的功能
-
建立与已确定的软件需求的对应关系
-
确定模块间的调用关系
-
确定模块间的接口
-
评估模块划分的质量
-
-
处理方式设计
-
算法
-
算法和模块间的控制方式
-
周转时间
-
响应时间
-
吞吐量
-
精度
-
-
确定外部信号的接收和发送形式
-
-
数据结构设计
-
数据完整性和安全性的设计
-
确定输入,输出文件的详细的数据结构
-
结合算法设计,确定算法所必需的逻辑数据结构及其操作
-
确定对逻辑数据结构所必需的那些操作的程序模块(软件包)
-
限制和确定各个数据设计决策的影响范围
-
数据的保护性设计
-
-
可靠性设计
确定软件可靠性和其它质量指标,考虑相应措施,以使得软件易于修改和易于维护
-
文档编写
-
评审
-
-
详细设计
对每个模块要完成的工作进行具体描述,将软件的体系结构按自顶向下方式,对各个层次的过程细节和数据细节逐层细化
模块:
-
功能
-
逻辑
-
状态
-
-
编写设计说明书提交评审
程序流程图:
N-S图:
软件模块化设计
模块是一个独立命名的,具有明确定义的输入、输出和特性的程序实体,可以通过名字访问,可以单独编译。
把一个大型软件系统的全部功能按一定原则合理的划分成若干个模块,每个模块完成一个特定子功能,所有模块以某种结构形式组成一个整体就是软件的模块化设计
可以简化软件的设计和实现,提高软件的可理解性和可测试性,并使软件更容易得到维护。
模块独立性
模块独立性是指开发具有独立功能而和其他模块没有过多关联的模块。每个子模块完成一个相对独立的特定子功能,并且和其他模块之间的关系尽可能简单。
模块独立性可以由两个定性标准度量:模块自身的内聚和模块之间的耦合
内聚按从弱到强分为七种:
-
偶然性内聚:模块内的各个任务在功能上没有实质性的联系,纯属偶然因素组合为块内各个互不相干的任务
-
逻辑性内聚:模块通常由若干个逻辑功能相似的任务组成,通过模块外引入一个开关量来选择其一执行,这种内聚增大了模块间的耦合性
-
时间性内聚:模块内的各个任务由相同的执行时间联系在一起,如初始化模块
-
过程性内聚:模块内各个任务必须按某一特定次序执行
-
通信性内聚:模块内部的各个任务靠公用数据联系在一起,即均使用同一个输入数据或产生同一个输出数据
-
顺序性内聚:模块内的各任务是顺序执行的,上一个任务的输出是下一个任务的输入
-
功能性内聚:模块的各个成分结合在一起完成一个特定的功能
耦合按从弱到强分为七种:
-
非直接耦合:同级模块相互之间没有信息传递,属于非直接耦合
-
数据耦合:调用下属模块时,如果交换的都是简单变量,便构成数据耦合。
-
特征耦合:调用下属模块时,如果交换的是数据结构就构成特征耦合。
-
控制耦合:模块间传递的不是一般的数据,而是作为控制信息的开关值或标志量
-
外部耦合:一组模块访问同一个全局变量
-
公共耦合:一组模块访问同一个全局性数据结构
-
内容耦合:一个模块可以直接调用另一个模块中的数据或直接转移到另一个模块中去,或者一个模块有多个入口。
编码测试
编码风格
清晰第一,效率第二
测试分类
-
单元测试
查找各模块在功能和结构上存在的问题,主要采用白盒测试
步骤:
-
模块接口测试
-
局部数据结构测试
-
路径测试
-
错误处理测试
-
边界测试
-
-
组装测试
将已测试过的模块按顺序组装
-
一次性组装方式
-
增值式组装方式
-
混合增殖式
-
-
确认测试
验证软件的功能和性能及其它特性是否与用户的要求一致
-
有效性测试:在模拟环境下黑盒测试
-
软件配置复查
-
验收测试:使用生产中的实际数据测试
-
-
系统测试
在实际运行环境下,对计算机系统进行一系列的组装测试和确认测试。
软件测试原则
-
尽早地和不断地进行软件测试
-
测试用例应由测试输入数据和对应的预期输出结果两部分组成。
-
程序员应避免检查自己的程序。
-
设计测试用例,应包括合理的输入条件和不合理的输入条件。
测试方法
黑盒测试
只依据程序的需求规格说明书,检查程序的功能是否符合它的功能说明
黑盒测试方法是在程序接口上进行测试
是否有不正确或遗漏了的功能?
在接口上,输入能否正确地接受? 能否输出正确的结果?
是否有数据结构错误或外部信息(例如数据文件)访问错误?
性能上是否能够满足要求?
是否有初始化或终止性错误?
测试用例设计:
-
等价类划分:完全不考虑程序的内部结构,只依据程序的规格说明来设计测试用例。
-
有效等价类:对程序的规范有意义,合理的输入数据所构成的集合
-
无效等价类:对程序的规范无意义,不合理的输入数据所构成的集合
如果已划分的等价类中个元素在程序中的处理方式不同,则应该将这个等价类进一步划分
设计每个测试用例时使其尽可能多地覆盖尚未覆盖的有效等价类/只覆盖一个无效等价类直到所有有效/无效等价类均被覆盖
-
-
边界值分析:确定边界情况。应当选取正好等于,刚刚大于,或刚刚小于边界的值做为测试数据,而不是选取等价类中的典型值或任意值做为测试数据。
-
错误推测法:列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据它们选择测试用例。
-
因果图
白盒测试
此方法把测试对象看做一个透明的盒子,它允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择测试用例
逻辑覆盖:以程序内部的逻辑结构为基础的设计测试用例的技术。它属于白盒测试。
语句覆盖:设计若干个测试用例,运行被测程序,使得每一可执行语句至少执行一次。
判定/分支覆盖:使得程序中每个判断的取真分支和取假分支至少经历一次。
条件覆盖:使得程序中每个判断的每个条件的可能取值至少执行一次。
判定-条件覆盖:判断每个条件的所有可能取值至少执行一次,每个判断中的每个条件的可能取值至少执行一次。
路径测试:覆盖程序中所有可能的路径
运行维护
-
改正性维护
-
适应性维护
-
完善性维护
软件过程模型
传统模型
瀑布模型
接收上一项活动的工作结果作为输入,然后实施该活动并将工作结果传给下一项活动。同时,在开始下一个阶段活动之前需要评审该项活动的实施,若确认则进行下一项活动,否则返回前面或者更前面的活动。
优点
-
提供按阶段划分的检查点
-
可在迭代模型中应用瀑布模型
缺点
-
各阶段完全固定,阶段之间产生大量文档,极大地增加了工作量
-
因为是线性开发,所以只能在末期看到开发结果,增加了开发风险
-
不灵活,不能适应用户的需求变化
增量模型
即一系列增量的方式开发系统,首先实现基本需求,之后客户对每一个增量的使用和评估作为下一个增量发布的新特征或功能
优点:
-
能在较短的时间内向用户提交可完成部分工作的产品
-
将待开发的软件系统模块化,可以分批次地提交软件产品,使用户可以及时了解软件项目的进展
-
以组件为单位进行开发降低了软件开发的风险。一个开发周期内的错误不会影响到整个软件系统
-
开发顺序灵活。开发人员可以对组件的实现顺序进行优先级排序,先完成需求稳定的核心组件。当组件的优先级发生变化时,还能及时地对实现顺序进行调整
缺点:
-
由于各个构件是逐渐并入已有的软件体系结构中的,所以加入构件必须不破坏已构造好的系统部分,这需要软件具备开放式的体系结构
-
在开发过程中,需求的变化是不可避免的。增量模型的灵活性可以使其适应这种变化的能力大大优于瀑布模型和原型模型,但也很容易退化为边做边改模型,从而是软件过程的控制失去整体性
-
如果增量包之间存在相交的情况且未很好处理,则必须做全盘系统分析,这种模型将功能细化后分别开发的方法较适应于需求经常改变的软件开发过程
螺旋模型
每一个周期都包括需求定义,风险分析,工程实现和评审四个阶段,软件开发过程每迭代一次,软件开发又前进一个层次。
螺旋模型引入风险识别,分析和控制,把软件项目分解成一个个小项目,每个小项目都标识主要风险
优点:
-
对可选方案和约束条件的强调有利于已有软件的重用,也有助于把软件质量作为软件开发的一个重要目标
-
减少了过多测试(浪费资金)或测试不足(产品故障多)所带来的风险
-
在螺旋模型中维护只是模型的另一个周期,在维护和开发之间并没有本质区别
缺点
-
采用螺旋模型需要具有相当丰富的风险评估经验和专门知识,在风险较大的项目开发中,如果未能够及时标识风险,势必造成重大损失
-
过多的迭代次数会增加开发成本,延迟提交时间
原型模型
它是快速建立起来的可以在计算机上运行的程序,它所能完成的功能往往是最终产品能完成的功能的一个子集;它没有固定的生存期;从需求分析到最终产品都可作原型;它必须快速、廉价;它是迭代过程的集成部分
优点:
-
减少需求不明确带来的风险
-
软件产品的开发基本上是线性进行的
缺点:
-
构造原型采用的技术和工具不一定主流.
-
快速建立起来的系统加上连续的修改可能导致原型质量低下
-
设计者在质量和原型中进行折中
-
客户意识不到一些质量问题
面向对象分析
面向对象模型
-
用例模型:指明了系统应该“做什么”,即系统的功能。
-
逻辑模型:描述系统的逻辑组成,包括对象模型、类模型和包模型
-
交互模型:描述系统中对象的交互及其行为,规定在何种状态下,接受什么事件的触发而“做什么”
-
实现模型:描绘系统实现的构件组成和依赖关系
-
部署模型:对系统硬件结构的抽象描述,对系统物理结点(计算机或设备)、结点间的连接关系(网络连接类型、协议和带宽等)和构件部署在哪些结点上(代码分配与部署)进行建模。
统一建模语言UML
UML是一种基于面向对象的可视化建模语言。UML用丰富的图形符号隐含表示了模型元素的语法,并用这些图形符号组成元模型表达语义,组成模型来描述系统的结构(或称为静态特征)以及行为(或称为动态特征)。
模型元素
模型结构
四个抽象层次
-
元元模型:定义了描述元模型的语言
-
元模型:定义了元类、元属性、元操作等一些概念
-
模型:定义了描述信息领域的语言
-
用户模型:模型的实例,用于表达一个模型的特定情况
UML视图
UML主要是用来描述模型的。它可以从不同视角为系统建模,形成不同的视图(View)。每个视图是系统完整描述中的一个抽象,代表该系统一个特定的方面;每个视图又由一组图(Diagram)构成,图包含了强调系统某一方面的信息。
UML规范中,将图分为两大类:
-
结构图:用例图、类图、对象图、构件图、部署图
-
行为图:状态图、时序图、协作图、活动图
四种视图
-
用例视图
从用户角度表达系统功能,使用用例图和活动图来描述;
-
逻辑视图
主要使用类图和对象图描述系统静态结构;用状态图、时序图、协作图和活动图描述对象间实现给定功能时的动态协作关系。
-
构件视图
展示系统实现的结构和行为特征,用构件图描述;
-
部署视图
展示系统的实现环境和构件是如何在物理结构中部署的,用部署图描述。
面向对象分析过程
面向对象分析阶段主要任务是获取用户的需求,并构建系统初步的逻辑模型。
用例建模
获取用户的需求,构建用例模型。
-
识别外部用户
-
场景分析
-
构建用例图
-
构建活动图
领域与业务建模
目的是建立系统的领域模型。
-
抽取领域对象:确定类或对象
-
构建领域模型:描述对象或类之间的关系
-
构建初步的交互模型:对象交互模型
类图
-
边界类: 边界类用于建立系统与其参与者之间交互的模型,表示用户界面、系统接口、硬件接口。每个边界类至少应该与一个参与者有关,反之亦然。
-
控制类:控制类代表协调、排序、事务处理以及其他对象的控制,经常用于封装与某个具体用例有关的控制。
-
实体类:实体类用于对长效持久的信息建模。大多数情况下,实体类是直接从业务对象模型中相应的业务实体类得到的。
类图描述系统的逻辑组成。
一个系统逻辑上由一组类组成,这些类在系统运行时实例化出对象,这些对象通过协作完成系统的功能。
类图由类、关联关系和重数组成。
重数是指类与类之间的关联关系中,一个类的实例与另一个类的实例之间的数量关系。重数通常表示在关联关系中,一个类的实例可以与另一个类的实例建立多少个连接。重数用数学符号来表示。具体画法不同地方教的不一样,参考看上图。
用例图
-
参与者:与系统交互的用户或其他软硬件系统,用小人形表示。
-
用例:系统中执行的一系列动作,用椭圆表示。
-
关系:参与者与用例、参与者之间、用例之间的联系。
-
主题:一组用例描述的系统或子系统,用矩形框表示, 。
参与者之间的关系:泛化关系
参与者与用例之间的关系:关联关系
用例之间的关系
-
包含关系:一个用例(基础用例)的行为包含另外一个用例(被包含用例)的行为。基础用例依赖于包含用例的执行结果。包含关系是通过在
依赖关系上应用<<include>>构造型(衍型)来表示的。箭头的方向是从基础用例指向被包含的用例。
(1) 如果两个以上用例有重复的功能,则可以将重复的功能分解到另一个用例中。其他用例可以和这个用例建立包含关系。
(2) 一个用例的功能太多时,可以用包含关系创建多个子用例。
-
扩展关系:扩展用例可以在基础用例之上添加新的行为,基础用例必须声明某些特定的扩展点,扩展用例只能在这些扩展点上扩展新的行为,
将扩展用例的事件流在一定的条件下按照相应的扩展点插入到基础用例中。 扩展关系是通过在依赖关系上应用<<extend>>构造型(衍型)
来表示的。
箭头方向由扩展用例指向基础用例。
-
泛化关系
一个用例可以被特别列举为一个或多个子用例,这被称为用例泛化。当多个用例共同拥有一种类似的结构和行为的时候,可以将它们的共性抽象成为父用例,其他的用例作为泛化关系中的子用例。泛化关系表示的是一般与特殊的关系。
eg:
某酒店订房系统描述如下: (1) 顾客可以选择在线预订,也可以直接去酒店通过前台服务员预订; (2) 前台服务员可以利用系统直接在前台预订房间; (3) 不管采用哪种预订方式,都需要在预订时支付相应订金; (4) 前台预订首选通过现金形式进行订金支付,若现金不足,则只能通过信用卡形式进行订金支付,但是网上预订只能通过信用卡进行支付; (5) 利用信用卡进行支付时需要和信用卡系统进行通信; (6) 客房部经理可以随时查看客房预订情况和每日收款情况。 构造该系统的用例模型。
顺序图
顺序图是用来描述对象自身及对象间信息传递顺序的视图。它用来表示用例中的行为顺序。当执行一个用例行为时,顺序图中的每条消息对应了一个类操作或状态机中引起转换的触发事件。它着重显示了参与相互作用的对象和所交换消息的顺序。顺序图用一个二维图描述系统中各个对象之间的交互关系,其中,纵轴是时间轴,时间沿竖线向下延伸,横轴代表了参与相互作用的对象。
顺序图的主要元素:
-
对象:参与交互的类的实例,对象之间可以发送消息和接收消息。
-
参与者:描述本次交互的发起者,即用例的驱动者。用小人形状表示。
-
生命线:生命线用于描述对象的生存周期,对象下方的虚线就是该对象的生命线。
-
激活条:表示控制焦点的控制期,指活动者或对象处于执行状态的时间段。用矩形条表示。
-
消息:消息用于描述对象间交互的方式及内容。
-
同步消息:一个对象向另一个对象发出同步消息后,将处于阻塞状态,一直等到另一个对象的回应。
表示方式:
-
异步消息:一个对象向另一个对象发出异步消息后,这个对象可以进行其他的操作,不需要等到另一个对象的响应。
表示方式:
-
返回消息:表示从过程调用返回。
表示方式:
-
简单消息:不区分同步或异步。
表示方式:
-
状态图
描述系统的动态行为
主要元素:
-
状态:指对象在事件发生之间某时刻所处的情形,用圆角矩形表示。
-
转移:指两个状态之间的关系,它表明当某事件发生时,对象从先前状态转换到后来的状态,用带有标记事件的箭头表示。
-
事件:某个事情的发生。
-
初始状态:当实例创建时,对象所处的状态。
软件项目管理
软件规模度量
书p294-295
代码行数LOC
千条代码行数KLOC=LOC/1000
未调整功能点UFP=∑某信息域期望数目x该信息域项加权因子
总影响程度DI=∑十四种中每种因素影响值(0~5) 总值在0~70
计算技术复杂性因子TCF=0.65+0.01xDI 总值在0.65~1.35之间
扩展功能点FP=UFPxTCF
规模期望
书p297
通过乐观,可能,悲观三个规模值(LOC/FP)加权平均得到
EV=(乐观值x1+可能值x4+悲观值x1)/6
成本估算
参考书p298例题
FP
平均生产率:FP/pm
项目工作量pm(人/月)FP/平均生产率
成本=FP*每FP的成本=FPx一个劳动力每月价格/平均生产率
LOC
平均生产率:LOC/pm
其他计算参考FP