软件工程(2)
软件的概念
软件= 程序+ 数据+ 文档
(1) 程序:按事先设计的功能和性能需求执行的指令序列
(2) 数据:是程序能正常操纵信息的数据结构
(3) 文档:与程序开发、维护和使用有关的图文材料
双重作用:软件一方面是一种产品,另一方面是开发其他软件产品的工具。
软件分类
(1)功能分类:系统软件、支撑软件、应用软件
(2)服务对象:项目软件、产品软件
软件的特征
1、软件是开发的或者是工程化的,并不是制造的
2、软件开发环境对产品影响较大
3、软件开发时间和工作量难以估计
4、软件会多次修改
5、软件的开发进度几乎没有客观衡量标准
6、软件测试非常困难
7、软件不会磨损和老化
8、软件维护易产生新的问题
9、软件生产是简单的拷贝
软件危机
在计算机软件的开发和维护过程中所遇到的一系列严重问题。
项目超出预算、项目超过计划完成时间、软件运行效率很低、软件质量差、软件通常不符合要求、项目难以管理并且代码难以维护、软件不能交付。
原因
客观:软件本身特点——(逻辑部件,规模庞大)
主观:不正确的开发方法——(忽视需求分析,错误认为:软件开发=程序编写,轻视软件维护)
软件工程定义
(1)应用系统化的、学科化的、定量的方法,来开发、运行和维护软件,即将工程化方法应用到软件。
(2)对(1)中各种方法的研究。
软工三要素【后面章节以此为纲吗】
工具:为软件工程的过程和方法提供自动化或半自动化的工具支持 。
方法:软件工程方法是完成软件工程项目的技术手段。分两类: 结构化方法和面向对象方法
过程:过程贯穿软件开发的各个环节,在各环节之间建立里程碑;管理者在软件工程过程中对软件开发的质量、进度、成本进行评估、管理和控制; 技术人员采用相应的方法和工具生成软件工程产品(模型、文档、数据、报告、表格等)
根基:质量焦点
发展过程
传统软件工程、对象工程、过程工程、构件工程。
软件过程(2)
软件工程是一种层次化技术
软件生命周期(龙说关注各个阶段产出,不过这图确实是有用。)
指软件产品或软件系统从定义、设计、投入使用到被淘汰的全过程。
软件过程概念
软件过程是在工作产品构建过程中,所需完成的工作活动、动作和任务的集合。
活动主要实现宽泛的目标
动作包含了主要工作产品生产过程中的一系列任务
任务关注小而明确的目标,能够产生实际产品
软件过程模型
是软件开发全部过程、活动和任务的结构框架。
直观表达软件开发全过程,明确规定要完成的主要活动、任务和开发策略。
软件过程评估
能力成熟度模型CMM(Capability Maturity Model)是迄今为止学术界和工业界公认的有关软件工程和管理实践的最好的软件过程评估模型。
分级:【感觉非常有道理!有借鉴意义】
(1)初始级 有能力的人和个人英雄主义
(2)可重复级 基本项目管理
(3)已定义级 过程标准化
(4)量化管理级 量化管理
(5)优化级 持续的过程改进
瀑布模型
软件开发过程与软件生命周期是一致的,也称经典的生命周期模型。
特点:
阶段间具有顺序性和依赖性。
推迟实现的观点。
每个阶段必须完成规定的文档; 每个阶段结束前完成文档审查,及早改正错误。以文档为驱动。
缺点
增加工作量
各个阶段的划分完全固定,阶段之间产生大量的文档,极大地增加了工作量;
开发风险大
由于开发模型是线性的,用户只有等到整个过程的末期才能见到开发成果,从而增加了开发的风险;
早期错误发现晚
早期的错误可能要等到开发后期的测试阶段才能发现,进而带来严重的后果。
不适用于需求变化的场合
适用于:系统需求明确、技术成熟、工程管理较严格的场合,如军工、航天、医疗。
V模型(瀑布变种)
龙老师说记住对应关系。
原型模型——思想是首先实现软件的最核心的、最重要的功能
原型(prototype):
一个部分开发的产品,使客户和开发人员能够对计划开发的系统的相关方面进行检查。
结果:抛弃原型、把原型发展成最终产品。
优点:减少需求不明带来的风险。
缺点:
- 构造原型采用的工具和技术不一定主流;
- 设计者在质量和原型中进行折中;
- 客户意识不到一些质量问题。
适用场合:客户定义一个总体目标集,但是他们并不清楚系统的具体输入输出;或开发者不确定算法的效率、软件与操作系统是否兼容以及客户与计算机交互的方式。
增量模型
增量:满足用户需求的一个子集,能够完成一定功能、小而可用的软件。
增量方式分为:增量方式(增加新功能)和迭代方式(改进)
特点:
• 增量模型从部分需求出发,先建立一个不完整的系统,通过测试运行这个系统,取得经验和反馈,进一步使系统扩充和完善
• 增量模型结合了原型模型的基本要素和迭代的特征,采用了基于时间的线性序列,每个线性序列都会输出该软件的一个“增量”
• 每个增量的开发可用瀑布或快速原型模型。
优点:
- 不需要提供完整的需求, 只要有一个增量包出现,开发就可以进行。
- 在项目的 初始阶段不需要投入太多的人力资源。增量可以 有效地管理技术风险。
- 产品逐步交付,能较好的适应需求变化。
- 开放式体系结构 ,便于维护。
- 软件能够更早的投入市场。
缺点:每个增量必须提供一些系统功能,这使得开发者很难根据客户需求给出大小适合的增量。软件必须具备开放式体系结构(困难)。易退化成边做边改的方式,使软件过程控制失去整体性
适用场合:开发中需求可能变化、具有较大风险、或希望尽早进入市场的项目。
螺旋模型
把开发活动和风险管理结合起来控制风险,强调风险管理,因此该模型适用于大型系统的开发。
模型结合了瀑布模型和原型模型的特点。
优点:
- 特别强调原型的可扩充性和可修改性,原型的进化贯穿整个软件生存周期,这将有助于目标软件的适应能力。支持用户需求的动态变化。
- 易于为用户和开发人员共同理解,还可作为继续开发的基础,并为用户参与所有关键决策提供了方便。
- 螺旋模型为项目管理人员及时调整管理决策提供了方便,进而可降低开发风险。
缺点:
- 如果每次迭代的效率不高,致使迭代次数过多,将会增加成本并推迟提交时间;
- 使用该模型需要有相当丰富的风险评估经验和专门知识,要求开发队伍水平较高。
适用场合:
适用于需求不明确或者需求可能发生变化的大型复杂的软件系统。
喷泉模型
是一种以用户需求为动力,以对象为驱动的模型,主要用于描述面向对象的软件开发过程
优点:各个阶段没有明显的界限,开发人员可以同步进行开发。其提高软件项目开发效率,节省开发时间。
缺点:由于喷泉模型在各个开发阶段是重叠的,在 开发过程中需要大量的开发人员,不利于项目的管理。此外这种模型 要求严格管理文档 ,使得审核的难度加大,尤其是面对可能随时加入各种信息、需求与资料的情况。
敏捷开发
敏捷软件过程是基本原理和开发准则的结合
优点: 对变化和不确定性有更快更敏捷的反应。在 快速的同时保持可持续的开发速度。能较好地适应商业竞争环境下对小项目提出的 有限资源和有限开发时间的约束
缺点:极限编程中的测试驱动开发可能会导致 系统通过了测试但不是用户期望的。 重构而不降低体系结构的质量是困难的。用于 大型项目有很多问题
选择模型【在不同的条件下选择相应的思路,对我有启发】
1.前期需求明确的情况下,尽量采用瀑布模型
2.用户无系统使用经验,需求分析人员技能不足的情况下,尽量借助原型模型
3.不确定因素很多,很多东西无法提前计划的情况下,尽量采用增量模型或螺旋模型
4.需求不稳定或资金和成本无法一次到位的,尽量采用增量模型
6.对于完成多个独立功能开发的情况,可在需求分析阶段就进行功能并行,每个功能内部都尽量遵循瀑布模型
7.全新系统的开发必须在总体设计完成后再开始增量或并行
8.编码人员经验较少的情况下,尽量不要采用敏捷或迭代模型
9.增量、迭代和原型可以综合使用,但每一次增量或迭代都必须有明确的交付和出口原则
瀑布模型、增量模型、原型模型和螺旋模型的联系和区别
比较项 | 瀑布模型 | 原型模型 | 增量模型 | 螺旋模型 |
---|---|---|---|---|
是否事先定义大部分需求 | 是 | 无 | 无 | 是 |
每次迭代输出是否为产品 | 是 | 无 | 无 | 是 |
驱动方式 | 文档 | 用户 | 用户 | 风险 |
迭代周期内的过程模型 | 瀑布模型 | 瀑布模型 | 原型模型 | 可选 |
举例说明:若一个软件包含A、B、C、D四个功能,那么
瀑布模型输出结果为ABCD
原型模型输出结果为A’B’C’D’->ABCD
增量模型输出结果为A->AB->ABC->ABCD
螺旋模型输出结果为A1B1C1D1->A2B2C2D2->……->ABCD
需求分析(1)
需求分析的定义:
确定系统必须具有的功能和性能,系统要求的运行环境,并且预测系统发展的前景。
换句话说需求就是以一种 清晰 、简洁 、一致且无二义性的方式,对一个待开发系统中各个有意义方面的陈述的一个集合。
需求获取
用户目标、领域知识、投资者、运行环境、组织环境
采访、设定情景、原型、会议、观察商业工程和工作流。
十原则:倾听、有准备的沟通、有地位足够的人推动、最好当面沟通、记录决定、保持通力合作
需求分析的过程:需求确认与需求变更
需求确认:需求获取->需求提炼->需求描述->需求验证:
- 需求获取:软件需求的 来源以及软件工程师收集这些软件需求的方法。
- 需求提炼(需求分析):将用户需求 精确化、完全化,最终形成下一步的 需求规格说明书。核心在于建立分析模型。
- 需求描述:软件需求规格说明书(SRS)——软件系统的需求规格说明,是对待开发系统的行为的 完整描述。为了使用户和软件开发者双方对该软件的初始规定有一个共同的理解,使之成为整个开发工作的基础。
- 需求验证:重要性:如果在后续的开发或当系统投入使用时才发现需求文档中的错误,就会导致更大代价的返工。
需对文档进行:- 有效性检查:检查不同用户使用不同功能的有效性
- 一致性检查:在文档中,需求之间不应该冲突。
- 完备性检查:需求文档应该包括所有用户想要的功能和约束。
- 可行性检查:检查保证能利用现有技术实现需求。
需求类型/需求分析的分类
(1) 功能性需求:描述系统应该做什么,即为用户和其它系统完成的功能、提供的服务。
(2) 非功能性需求:必须遵循的标准,外部界面的细节,实现的约束条件,质量属性等等
(3) 非功能需求限定了选择解决问题方案的范围,如运行平台、实现技术、编程语言和工具等
分析模型描述工具
一个典型的软件系统使用数据结构(数据模型),执行操作(行为模型),并且完成数据值的变化(功能模型)
面向过程分析模型:基本思想 是用系统工程的思想和工程化的方法,根据用户至上的原则,自始自终按照 结构化、模块化,自顶向下 地对系统进行分析与设计。
结构化分析(Structured Analysis,简称SA),是面向数据流进行需求分析的方法。 结构化分析的主要思想是采取自顶向下逐层分解的分析策略,即面对一个复杂的问题,分析人员不可能一开始就考虑到问题的所有方面以及全部细节,采取的策略往往是分解,把一个复杂的问题划分成若干小问题,然后再分别解决,将问题的复杂性降低到人可以掌握的程度。
面向对象分析模型:由5个层次(主题层、对象类层、结构层、属性层和服务层)和5个活动(标识对象类、标识结构、定义主题、定义属性和定义服务)组成。
面向对象方法是一种运用对象、类、继承、封装、聚合、关联、消息、多态性等概念来构造系统的软件开发方法。 面向对象方法的解决问题的思路是从现实世界中的客观对象(如人和事物)入手,尽量运用人类的自然思维方式来构造软件系统,这与传统的结构化方法从功能入手和信息工程化方法从信息入手是不一样的。
面向过程—结构化分析方法
数据流图DFD
数据流图层次结构
与、或、异或。
加工 的命名注意事项
1)顶层的加工名就是整个系统项目的名字
2)尽量最好使用动宾词组,也可用主谓词组
3)不要使用空洞的动词
外部实体(数据源点/ /终点)
起到更好的理解作用,但不是系统中的事物
数据流
数据流可从加工流向加工,也可在加工与数据存储或外部项之间流动;两个加工之间可有多股数据流
1) 不要把控制流作为数据流。 2) 不要标出激发条件
每个加工至少有一个输入数据流和一个输出数据流。
数据流必须有一端是加工,而不能两端都是 外部项/数据存储。
面向对象
功能模型-用例图
用例建模用于描述系统需求,把系统当作黑盒,从用户的角度,描述系统的场景。
主要图形元素有以下几个:
参与者:是指外部用户或外部实体在系统中扮演的角色。可以是 人、其他系统、设备 或者时间等角色。
确定参与者:
开发人员可以通过回答以下的问题来寻找系统的参与者。
(1)谁将使用该系统的主要功能?
(2)谁将需要该系统的支持以完成其工作?
(3)谁将需要维护、管理该系统,以及保持该系统处于工作状态?
(4)系统需要处理哪些硬件设备?
(5)与该系统交互的是什么系统?
(6)谁或什么系统对本系统产生的结果感兴趣?
用例:对一组动作序列的描述,系统通过执行这一组动作序列为参与者产生一个可观察的结果。用例名往往用动宾结构命名
用椭圆形表述
• 说明了系统具有的一种行为模式
• 说明了一个参与者与系统执行的一个相关的事件序列
• 提供了一种获取系统需求的方法
• 提供了一种与最终的用户和领域专家进行沟通的方法
• 提供了一种测试系统的方法
执行关联: 参与者(Actor )执行用例(Use Case)之间的关系
- 关联: 参与者与用例之间的关系(其他都是用例之间的关系)。表示 参与者与用例之间的通信,任何一方都可发送或接受消息。
【箭头指向】:指向消息接收方,也可以不加箭头 - 泛化: 就是通常理解的继承关系,子用例和父用例相似,但表现出更特别的行为;子用例将继承父用例的所有结构、行为和关
系。子用例可以使用父用例的一段行为,也可以重载它。父用例通常是抽象的。
【箭头指向】:指向父用例 - 包含:包含(include)关系指的是两个用例之间的关系,其中一个用例(称为基本用例)的行为包含另一个用例(称为包含用例,inclusion use case)的行为。
【箭头方向】由基本用例指向分解出的用例。 执行基本用例的时候,每次都应该调用被包含用例, 被包含用例也可单独执行。 - 扩展:扩展关系是指用例功能的延伸,相当于为基础用例提供一个 附加功能。 扩展用例依赖于被扩展用例,不是完整的独立用例, 无法单独执行。在扩展关系中,一个基本用例执行时,可以执行、也可以不执行
【箭头方向】由扩展用例指向基本用例。
行为模型-活动图(泳道图)
是对用例的图形化!
• 每一步都是做某事的一个状态
• 执行步骤称为动作
• 描述哪些步骤被顺序执行、哪些可被并发地执行
• 控制流 – 控制从一个动作到下一个动作的流
在用例流中发现动作。
活动图别忘了开始和结束的标记,注意分叉的类型
开始:实心圆 结束:牛眼
转换可以分支及合并(钻石框) – (可选)计算线程【如果需要判断,也得在菱形外面加说明,如果有条件,要附上说明】
转换可以分叉及汇合(短横线)– 并发(并行)计算线程
这俩图还是建议好好看完PPT。
软件设计(1)
软件设计:软件系统或组件的架构、构件、接口和其他特性的定义过程及该过程的结果。
软件工程生命周期中的一个活动。进行软件编码的基础。
软件需求分析被转化为软件的内部结构。是连接用户需求和软件技术的桥梁。设计是软件工程技术的核心。
指导原则:
1 设计应该是一种架构
2 设计应该是模块化的
3 设计应该包含 数据、体系结构、接口和组件各个方面应该设计出系统所用的数据结构
应该设计出展现独立功能特性的各组件
应该设计出各组件与外部环境连接的各接口4 设计由软件需求分析过程中获得信息驱动,采用可重复使用的方法导出
5 设计应该采用正确清楚的表示法
概要设计:实现目标产品的总体框架,包括体系结构设计、数据设计、接口和组件设计。
其中体系结构是设计师概要设计的主要内容。
详细设计:对概要设计划分出来的模块分别去描述设计,以便能够编码实现
系统设计从数据、体系结构、接口和组件四方面进行设计。【自底向上】
八大概念【知道即可,不会让详细解释】
抽象、体系结构、设计模式、模块化、信息隐藏、功能独立、细化、重构。
其中,着重考察 体系结构、模块化、信息隐藏、功能独立。
抽象
忽略具体的信息将不同事物看成相同事物的过程, 参数化、规范化。
体系结构
含义:软件的整体结构 和 这种结构为系统提供 概念上完整性 的方式
表达方式:结构模型、框架模型、动态模型、过程模型、功能模型设计模式
在给定上下文环境中一类共同问题的共同解决方案,如抽象工厂
模块化
软件被划分为命名和功能相对独立的多个组件(通常称为模块),通过这些组件的集成来满足问题的需求
软件的模块性:程序可被智能管理的单一属性
理论依据:基于人类解决问题的观测数据
模块化基本问题 如何分解软件系统以达最佳的模块划分
设计标准:
- 分解性:可分解为子问题
- 组合性:组装可重用的组件
- 可理解性:可作为独立单元理解
- 连续性:需求小变化只影响单个模块
- 保护: 模块内异常只影响自身
信息隐藏
模块应该具有彼此相互隐藏的特性,模块内的信息(过程和数据)不可以被不需要这些信息的其他模块访问
功能独立
每个模块只负责需求中特定的子功能,并且从程序结构的其他部分看,该模块具有简单的接口
• 易于开发:功能被划分,接口被简化。
• 易于维护(和测试):次生影响有限,错误传递减少,模块重用。定性衡量标准:
• 内聚性:模块的功能相对强度
• 耦合性:模块之间的相互依赖程度
• 模块独立性强 = 高内聚低耦合精化
逐步求精的过程
与抽象的关系:
• 抽象使设计师确定过程和数据,但不局限于底层细节
• 精化有助于设计者在设计过程中揭示底层细节重构
不改变组件功能和行为条件下,简化组件设计(或代码)的一种重组技术
检查现有设计的冗余情况、未使用的设计元素、无效或不必要的算法、较差的构建方式或不恰当的数据结构,或任何其他可被更改从而优化设计的问题
面向过程设计技术概要
系统设计从体系结构、数据、接口和组件四方面进行设计。
数据设计
(有时也被称为数据架构)构建高层抽象(客户/用户的数据视图)的数据模型、信息模型
- 数据建模: 数据字典、E-R 图 、类图。
- 数据结构:计算机存储组织数据的方式。
- 数据库:按照数据结构来组织、存储和管理数据的仓库
体系结构设计
风格和模式简要分类:数据中心结构、数据流体系结构、调用和返回结构、层次结构、面向对象结构【图要认得出】
组织和细化两个基本问题:
- 控制结构:在架构内部如何实现管理控制?是否有不同的控制架构存在
- 数据传递:组件之间如何进行数据传递?数据流是否连续,或者传递给系统的数据对象是否零散
接口设计(含界面设计)
• 允许用户操作控制(用户为中心)
• 减少用户记忆负担
• 保持界面一致组件设计:面向过程(函数、模块)、面向对象(类与操作)
在过程设计、详细设计,位于数据设计、体系结构设计和接口设计完成之后面向过程的总体设计
1 首先研究、分析和审查数据流图。 从软件的需求规格说明中弄清数据流加工的过程,对于发现的问题及时解决。
2 然后根据数据流图决定问题的类型。数据处理问题典型的类型有两种:变换型和事务型。针对两种不同的类型分别进行分析处理。
3 由数据流图推导出系统的初始结构图。
4 利用一些启发式原则来改进系统的初始结构图,直到得到符合要求的结构图为止。(系统结构图)
5 修改和补充数据词典。
软件体系结构是系统的一个或多个结构,它包括软件构件、构件的外部可见属性、以及它们之间的相互关系。
风格和模式简要分类:数据中心结构、数据流体系结构、调用和返回结构、面向对象结构、层次结构【图要认得出】
流程图(flow chart)
利用各种方块图形、线条及箭头等符号来表达解决问题的步骤及进行的顺序;是算法的一种表示方式。
基本结构
顺序结构、选择结构(二元、多重)、循环结构(while-do\do-while)【可以看看陈安龙出的题】
其他面向过程组件设计方法:盒图(N-S图)、PDL(程序设计语言)、判定表、判定图
面向对象的设计
分为系统架构设计、用例设计、类设计、数据库设计、用户界面设计。
架构设计
架构设计的目的是要勾画出系统的总体结构,这项工作由经验丰富的架构设计师主持完成。
输入:用例模型、分析模型。 输出:物理结构、子系统及其接口、概要的设计类。
用例设计
进一步细化用例
根据分析阶段产生的高层类图和交互图,由用例设计师研究已有的类,将它们分配到相应的用例中。
检查每个用例功能,依靠当前的类能否实现,同时检查每个用例的特殊需求是否有合适的类来实现。
细化每个用例的类图,描述实现用例的类及其类之间的相互关系,其中的通用类和关键类可用粗线框区分,这些类将作为项目经理检查项目时的重点。
类设计
类是包含信息和影响信息行为的逻辑元素。类的符号是由三个格子的长方形组成,有时下面两个格子可以省略。
类间关系
(1) 关联关系:关联是一种结构化的关系,指一种对象和另一种对象有联系。
(2) 聚合关系:指的是整体与部分的关系。
(3) 泛化关系:泛化也就是继承关系
(4) 组合关系:也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。
(5) 依赖关系:是一种使用关系,特定事物的改变有可能会影响到使用该事物的事物
组合是一种较为紧密的关系,从生命周期上看,部分和整体是共存亡的关系。 聚合则是一种较为松散的关系,部分和整体的生命周期未必一致。
不同的类
实体类用于对必须存储的信息和相关行为进行建模。源于业务模型中的业务实体
边界类用于参与者与用例之间、有交互的用例间、用例与系统边界之外交互时,
控制类来源于对用例场景中动词的分析和定义,主要起到协调对象的作用,例如从边界类通过控制类访问实体类,或者实体类通过控制类访问另一个实体类。
类设计三步
定义类的属性,类的属性反映类的特性,通常属性是被封装在类的内部,不允许外部对象访问。
原则:尽量使用已有的类型,一个类不要太复杂,坚持简单的原则。
定义类的操作
一个类可能被应用在多个用例中,由于它在不同用例中担当的角色不同,所以设计时要求详细周到。
检查类在每个用例中实现是否合适,补充必要操作;考虑特殊情况。定义类之间的关系
UML顺序图
用例常常被细化为一个或多个顺序图。它还能用来记录一个存在于系统的对象现在如何交互。
当强调按时间展开信息的传送时,一般使用顺序图建模技术。
- 顺序图是强调消息时间顺序的交互图。
- 顺序图描述了对象之间传送消息的时间顺序,用来表示用例中的行为顺序。
- 顺序图将交互关系表示为一个二维图。即在图形上,顺序图是一张表,其中显示的对象沿横轴排列,从左到右分布在图的顶部;而消息则沿纵轴按时间顺序排序。创建顺序图时,以能够使图尽量简洁为依据布局。
四个元素
对象(符号和对象图中对象所用的符号一样)、生命线、消息、激活。
对象置于顺序图的顶部意味着在交互开始的时候对象就已经存在了,否则表示对象是在交互的过程中被创建的。
一般最多两个参与者,他们分列两端。启动这个用例的参与者往往排在最左边;接收消息的参与者则排在最右端;
对象从左到右按照重要性排列或按照消息先后顺序排列
每个对象都有自己的生命线(垂直的虚线),用来表示在该用例中一个对象在一段时间内的存在,生命期结束,则用注销符号表示。
激活表示该对象被占用以完成某个任务,去激活指的则是对象处于空闲状态、在等待消息。
面向对象方法中,消息是对象间交互信息的主要方式。
结构化程序设计中,模块间传递信息的方式主要是过程(或函数)调用。
消息分类:
同步消息:消息名称通常就是被调用的操作名称。【普通箭头】
异步消息表示发送消息的对象不用等待回应的返回消息,即可开始另一个活动。【半箭头】
一个对象也可以将一个消息发送给它自己,这就是反身消息。【指向自己】
返回消息是顺序图的一个可选择部分,它表示控制流从过程调用的返回。【返回的虚线箭头】
一般可以缺省,隐含表示每一个调用都有一个配对的调用返回。
要注意创建和销毁临时对象的画法
步骤:Ø确定交互的范围、Ø识别参与交互的对象和活动者、Ø设置对象生命线的开始和结束、Ø设置消息、Ø细化消息
面向对象设计原则【有用】:
强调定义软件对象,并且使这些软件对象相互协作来满足用户需求。
注意:
• 对接口进行设计
• 发现变化并且封装它
• 先考虑聚合然后考虑继承强内聚:一个类的属性和操作全部都是完成某个任务所必须的,其中不包括无用的属性和操作。
弱耦合:耦合主要指不同对象之间相互关联的程度。如果一个对象过多地依赖于其它对象来完成自己的工作,则不仅使该对象的可理解性下降,而且还会增加测试、修改的难度,同时降低了类的可重用性和可移植性。
当两个对象必须相互联系时,应该通过类的公共接口实现耦合,不应该依赖于类的具体实现细节。可重用性:
• 尽量使用已有的类,包括开发环境提供的类库和已有的相似的类;
• 如果确实需要创建新类,则在设计这些新类时考虑将来的可重用性框架:
框架是一组可用于不同应用的类的集合。框架中的类通常是一些抽象类并且相互有联系,可以通过继承的方式使用这些类。
质量保证(1)
质量保证(QA)概念
定义:系统地监测和评估一个工程的各个方面,以最大限度地提高由生产过程实现的质量的最低标准。
原则:适合用途:该产品应符合预期的目的 一次成功:错误应该被淘汰
软件质量:明确表示是否符合功能和性能要求,明确地记载开发标准和期望的隐性特点
- 符合明确规定的功能和性能要求(前期约定)
- 符合明确的开发标准(明确标准)
- 符合所有软件开发专业的共性、隐性标准,如易用性、可维护性等(共性期望)
软件质量保证(SQA)
遵照一定的软件生产标准、过程和步骤对软件质量进行评估的活动
评估指标
可靠性是一个持续性的状态,更多地强调系统自身;
可用性是一个短暂的状态,更多地强调外部的触发。
一个人如果随叫随到,但是时不时偷懒,就是高可用、低可靠;而如果他经常找不到人,但干活很负责,就是低可用、高可靠。
V模型!
要注意水平对应关系!(这个和之前瀑布的图差了很多)
- 单元测试的主要目的是验证软件模块 是否按详细设计的规格说明正确运行。
单元测试需要从程序的内部结构出发设计测试用例。多个模块可以平行地独立进行单元测试。
测试内容:模块接口 + 局部数据结构 + 边界条件 + 独立路径 + 出错处理
主要内容:模块接口测试(数据流、内外存交换)、局部数据结构测试、路径测试、错误处理测试、边界测试(流边界、关键路径)
测试环境:模块并非独立程序,进行测试时,要考虑它和外界的联系,需用一些辅助模块去做相应模拟。
- 驱动模块:用来模拟被测试模块的上一级模块,相当于被测模块的主程序。
- 桩模块:模拟被测试的模块所调用的模块,而不是软件产品的组成的部分。
- 集成测试主要目的是检查多个模块间 是否按概要设计说明的方式协同工作。
将软件集成起来后进行测试。检查诸如两个模块单独运行正常,但集成起来运行可能出现问题的情况。
自顶向下:将模块按系统程序结构,沿控制层次自顶向下进行集成。
可首先实现和验证一个完整的软件功能。桩模块的开发量较大。
适用于:控制结构清晰稳定;高层接口变化较小;希望尽早能看到产品的系统功能行为,底层接口未定义或经常可能被修改。
自底向上:从软件结构最底层的模块开始,按照接口依赖关系逐层向上集成以进行测试。
不需要桩模块;必须编写驱动模块;缺陷的隔离和定位不如自顶向下。
适用于:底层接口比较稳定;高层接口变化比较频繁;底层组件较早被完成。
实际工作中,常综合使用:自底向上、自顶向下
SMOKE方法:
将已经转换为代码的软件构件集成为构造(build)。一个构造包括所有的数据文件、库、可复用的模块以及实现一个或多个产品功能所需的工程化构件。
每天将该构造与其他构造,及整个软件产品集成,进行冒烟测试。
- 系统测试的主要目的是验证整个系统 是否满足需求规格说明。
从用户使用的角度进行测试,将完成了集成测试的系统放在真实的运行环境下进行。
目的:功能确认和验证 测试方法:黑盒测试
系统测试是软件开发过程必不可少的一环,软件质量保证的最重要环节
测试内容:面向:外部输入层测试,如不做,则外部输入层向接口层转换的代码就没有得到测试。
• 功能性测试:在规定的一段时间内运行软件系统的所有功能,以验证有无严重错误
• 性能测试:检查系统是否满足需求规格说明书中的性能,常与压力测试结合
• 压力测试:检查在系统运行环境不正常乃至发生故障的情况下,系统可以运行到何种程度的测试。敏感性测试
• 恢复测试:克服硬件故障后,系统能否继续正常工作。并不对系统造成任何损害。
• 安全测试:检测系统的安全性、保密性措施是否发挥作用,有无漏洞
- 验收测试从最终用户的角度检查系统是否满足合同中定义的需求,以及以确认产品是否能符合业务上的需要。
时间:系统的有效性测试及软件配置审查通过之后。人员:以用户为主。软件开发人员和 QA(质量保证)人员也应参加
测试数据:实际生产数据。
主要形式:
根据合同的验收测试——系统测试子集再测试
用户验收测试:分为客户和最终用户
现场测试:α测试、β测试
α测试:是由公司内部的用户在 开发环境下进行的测试,模拟实际操作环境下进行的测试。
评价FLURPS特性(功能、本地化、可使用性、可靠性、性能和支持)。尤其界面和特色
开始时间:模块(子系统)测试完成后系统测试过程中产品达到一定的稳定和可靠程度后。
β测试:多个用户在实际使用环境下进行测试。这些用户返回有关错误信息给开发者。
用户记录所有问题(真实的、主观的),定期向开发者报告。
评价 产品的FLURPS。着重产品的支持性(文档、客户培训和支持产品生产能力)
开始时间:α测试达到一定的可靠程度时开始,测试的最后阶段,所有手册文本此阶段完全定稿
回归测试
指有选择地重新测试系统或其组件,以验证对软件的修改没有导致不希望出现的影响,以及系统或组件仍然符合其指定的需求。
Why:
测试中,如有缺陷修正、功能增加,变化的部分必须再测试。软件的修改可能会导致新的缺陷及其他问题。为防止,需再测试。
回归测试可以在所有的测试级别执行,并应用于功能和非功能测试中。范围:
- 缺陷再测试:重新运行所有发现故障的测试,而新的软件版本已经修正了这些故障。
- 功能改变的测试:测试所有修改或修正过的程序部分。
- 新功能测试:测试所有新集成的程序。
- 完全回归测试:测试整个系统。
软件缺陷
至少满足下列一个条件,称发生了一个软件缺陷
(1) 软件未实现产品说明书要求的功能。
(2) 软件出现了产品说明书指明不能出现的错误。
(3) 软件实现了产品说明书未提到的功能。
(4) 软件未实现产品说明书虽未明确提及但应该实现的目标。(xswl)
(5) 软件难以理解、不易使用、运行缓慢或者——从测试员的角度看——最终用户会认为不好。
验证(Verification)保证软件特定开发阶段的输出已经正确完整地实现了规格说明
(我们正确地构造了产品吗?)
确认(Validation)对于每个测试级别,都要检查开发活动的输出是否满足具体的需求或与这些特定级别相关的需求
(我们构造了正确的产品吗?)
测试(补救)
找出软件缺陷,并确保缺陷得以修复
质量保证(预防)
创建和执行改进、软件开发过程并防止软件缺陷发生的标准和方法。
质量与可靠性
功能性、可靠性、可维护性、可用性、效率、可移植性。
软件测试:目标是发现软件缺陷的存在
软件调试:目标是定位与修复缺陷
测试用例(test case):是测试输入、执行条件、以及预期结果的集合
是为特定的目的开发的,例如执行特定的程序路径或验证与指定的需求相符合。
设计格式:【输入的(oldpwd, newpwd, newpwdag),输出的(提示1,提示2)】
白盒测试
考虑系统或组件的内部机制的测试形式(如分支测试、路径测试、语句测试等),也称结构性测试或逻辑驱动测试。
逻辑覆盖 是以程序内部的逻辑结构为基础的设计测试用例的技术。
每条边设置个英文字母,每条路径设置个$L_i$
语句覆盖:就是设计若干个测试用例,运行被测程序,使得每一可执行语句至少执行一次。
分支覆盖/判定覆盖:使得程序中每个判断的取真分支和取假分支至少经历一次。
条件覆盖:使得程序中每个判断的每个条件的可能取值至少执行一次。只要每个可能都出现过就好,理论上最少2次就行。
- 条件组合覆盖:使得每个判断的所有可能的条件取值组合至少执行一次
一个判断里,可能有多个条件$T_1,T_2…T_n$,每个条件两种可能,组合起来就是$2^n$种。(还要做标记)
控制流图覆盖 是将代码转变为控制流图(CFG),基于其进行测试的技术
结点:符号○ ,表示一个或多个无分支的PDL语句或源程序语句。
边:箭头,表示控制流的方向。
汇聚节点:在选择或多分支结构中,分支的汇聚处应有一个汇聚结点。这个不能漏,不然算复杂度会错
区域:边和结点圈定的区域。对区域计数时,图形外的区域也应记为一个区域。
节点覆盖
对图中的每个节点,至少要有一条测试路径访问该节点显然,节点覆盖=语句覆盖
节点覆盖和语句覆盖是等价的。边覆盖
对图中每一个可到达的长度小于(无边图)等于1 的路径,中至少存在一条测试路径覆盖。显然,边覆盖包含节点覆盖,且边覆盖也可以实现分支覆盖。
路径覆盖
覆盖程序中所有可能的路径,
基本路径覆盖
独立路径:至少包含有一条在其它独立路径中从未有过的边的路径
找独立路径条数:V(G)(环路复杂度) = e(边数)−n(结点数)+2
开始的点被舍掉,连续的点,比如2,3和4,5被合并到一个节点
找基本路径:每次回溯上一个节点,即从最后一个节点倒推,如果能走新的路就走新的路。
黑盒技术
黑盒测试:忽略系统或组件的内部机制,仅关注于那些响应所选择的输入及相应执行条件的输出的测试形式
等价类划分:
把所有可能的输入数据,即 程序的输入域划分成若干部分,然后从每一部分中 选取少数有代表性的数据做为测试用例。
等价类:某个输入域的子集合。在该子集合中,各个输入数据对于揭露程序中的错误都是等效的。
有效等价类:对于程序的规格说明来说,是合理的,有意义的输入数据构成的集合。
无效等价类:对于程序的规格说明来说,是不合理的,无意义的输入数据构成的集合。
原则:
(1) 如果输入条件规定了取值范围,或值的个数(范围),则可以确立一个有效等价类和两个无效等价类。
(2) 如果输入条件规定了输入值的集合,或者是规定了“必须如何”的条件,这时可确立一个有效等价类和一个无效等价类。
(3) 如果输入条件是一个布尔量,则可以确定一个有效等价类和一个无效等价类。
(4) 如果规定了输入数据的一组值,而且程序要对每个输入值分别进行处理(不同于 2 )。这时可为 每一个输入值确立一个有效等价类,此外针对这组值确立一个无效等价类,它是所有不允许的输入值的集合。
(5) 如果规定了输入数据必须遵守的规则,则可以确立一个有效等价类(符合规则)和若干个无效等价类(从不同角度违反规则)。(比如,输入条件:学生的学院字段数据类型,那有效等价类:字符串型;无效等价类:整数、浮点、布尔型)
【2和5相比,5只是规定了一项规则,2直接规定了整个集合】
步骤:
列出表【输入条件、有效等价类、无效等价类】为每个等价类规定一个唯一编号
测试用例尽可能多地覆盖尚未被覆盖的有效等价类,仅覆盖一个尚未被覆盖的无效等价类
例:
边界值分析
对等价类划分方法的补充,大量的错误是发生在输入或输出范围边界上
闭区间:选择边界点、边界点加一个步长的点和边界点减一个步长设计测试用例
开区间:选择边界点、边界点范围内方向移动一个步长的点计测试用例。
上点,即边界上的点,不管是开区间还是闭区间。
内点,上点范围内的任意一点。
离点,离上点最近的点称为离点。开区间为上点范围内加一个步长,闭区间为上点范围外加一个步长。
比如[85,100],离点就是 84,101 (0,60),离点就是1,59, [60,75) 离点 59,74
所以一元函数有5个测试用例。
二元函数:
先列出每一个变量的上点、内点和离点(5*2)。
用第一个变量的上点、离点与第二个变量的内点配对设计4个测试用例
用第一个变量的内点与第二个变量的上点、离点配对设计4个测试用例
最后两个变量的内点配对形成最后一个测试用例,共设计9个测试用例。
多元函数类似,都是某个变量的上点、离点配上别的元的内点,再加上一个都是内点,共$4n+1$
黑盒还有一种状态测试。
在黑盒测试阶段,通过对状态的测试间接地加以验证功能
建立状态转换图->根据状态转换图设计测试用例。
灰盒测试:
介于白盒测试与黑盒测试之间的一种测试,多用于集成测试阶段,不仅关注输出、输入的正确性,同时也关注程序内部的情况
静态分析
不运行程序,通过检查和阅读等手段来发现错误并评估代码质量的测试技术
主要内容:检查需求、设计、代码(缺陷产生的可能由大到小)
类型:同事审查(初次)、走查(开发组内部进行)、审查(会议形式,开发组、测试组和相关人员联合进行)
项目管理(2)
项目管理:计划、协调、度量、监控、控制及报告等管理方法在软件开发和维护中的具体应用
以保证整个过程是系统的、有原则的、可量化的
四要素:人员(People)、产品(Product)、过程(Process)、项目(Project)。
关键业务领域:招聘、选拔、绩效管理、培训、薪酬、职业发展、组织和工作设计、团队/文化的发展。
在策划一个项目以前,应当建立产品的目标和范围,应考虑其他解决办法,以及技术和管理应当被约束。
软件开发的一个全面计划
理解成功项目管理的关键因素,掌握项目计划、监控和控制的一般方法
软件度量:
一种量化衡量方法,使得人们可以理解和把握软件项目的(生产)效率(或者所需要的劳动量)
目的:软件项目管理的成熟化也需要度量与数字化,目的是持续改进软件过程,并用于项目估算、质量控制、生产率评估等
面向规模【直接测量】:
通过对质量和(或)生产率的测量进行规范化而得到的,这些测量是根据开发过的软件的规模得到的。
- 千行代码( KLOC ): 这些代码指的是源代码,通过源代码的行数来直观度量一个软件程序有多大规模
- 生产率(PM):PM = L / E, L表示代码总量(单位:KLOC),E表示软件工作量(单位:人月)
- 每千行代码的平均成本( CKL ):CKL = S / L,S为软件项目总开销
- 代码出错率(EQRl):EQRl = Ne / L,Ne表示代码出错的行数
- 文档与代码比(Dl):Dl = Pd / L,Pd表示文档页数
简单易行,自然直观;但 软件开发初期很难估算出最终软件的代码行数,对短小精悍的程序不利
面向功能【间接测量】
功能点(Function Point, FP)法,项目开发初期就可估算出
方法:先算未调整功能点总计数 UFC,再算功能点 FP
$FP = UFC×TCF = UFC × (0.65 + 0.01×\sum F_i)$
UFC相关的五类组件:内部逻辑文件ILF、外部接口文件EIF、外部输入EI、外部输出EO、外部查询EQ。
至于14个复杂性调节因素 $F_i$从0【没有影响】到5【严重影响】
优点:与程序设计语言无关, 在开发前就可以估算出软件项目的规模
不足:没有直接涉及算法的复杂度,不适合算法比较复杂的软件系统,功能点计算主要靠经验公式,主观因素比较多
FP起到了代码行的作用,但是也可以换算,估计不考👇
项目估算
分两种
基于问题分解的估算
就是把问题分解成各个子系统,分别估算,最后合并。
三点期望法:估计期望值=(最大值+4×最可能值+最小值) / 6
基于LOC的估算:估算出各个子系统的代码行(直接主观猜)
用LOC或FP算出LOC总代码行或FP功能点数,然后结合历史数据
基于回归分析的经验估算模型
$E=A+B×(e_v )^ C$ 其中E是工作量(人月),$e_v$是估算变量(LOC或功能点)
COCOMO经验估算模型(COnstructive COst MOdel,构造性成本模型)
是一个综合经验模型,模型中的参数取值来自于经验值,并且综合了诸多的因素、比较全面的估算模型
用来根据KLOC算工作量和开发时间
模型层级
- 基本COCOMO模型:估算整个系统的工作量(包括维护)和软件开发和维护所需的时间
- 中间COCOMO模型:估算各个子系统的工作量和开发时间
- 详细COCOMO模型:估算独立的软构件,如各个子系统的各个模块的工作量和开发时间
EAF的取值(考虑15个因素) 建议取值范围[0.70-1.66] EAF的计算=$\prod F_i ( i=1..15)$
项目计划
对项目进行任务划分,定义任务之间的依赖关系,并进行时间估算和资源分配,确保以最佳的时间与成本输出满足质量要求的产品。
编制项目计划本质是一个优化问题。
项目计划可视化用甘特图
关键路径——在任务网络图中,从项目开始到项目完成有许多条路径,路径上所有弧权重之和最大的路径(路径最长)叫关键路径。
软件维护(2)
定义:由于软件产品出现问题或需要改进,而对代码及相关文档进行修改,
目的:对现有软件产品进行修改的同时保持其完整性
软件维护阶段一般要消耗软件生命周期中经费开支的大部分
四种基本类型:
完善性维护【一半以上】扩充软件功能、增强软件性能、 改进加工效率、 提高软件的可维护性
纠错性维护
适应性维护(环境变化)
预防性维护【最少】采用先进的软件工程方法对需要维护的软件或软件中的 某一部分(重新)进行设计、编制和测试
决定软件可维护性的主要因素:可理解性、可测试性、可修改性、可移植性、可重用性
影响软件可维护性的环境因素——软件维护的文档、软件的运行环境、软件的维护组织、软件维护质量。
软件维护技术
程序的理解:建立从问题/应用域到程序设计/实现域的映射集
程序理解的具体任务:
通过检查单个的程序设计结构,程序被表示成抽象语法树、符号表或普通源文本
尽量做到程序隐含信息的显性表示及程序内部关系的可视化
检查程序构造过程中的结构关系,明确表示程序组成部分之间的依赖关系。
软件再工程:
对现有软件进行仔细审查和改造,对其进行重新构造,使之成为一个新的形式,同时包括随之产生的对新形式的实现。
软件逆向工程:
分析目标系统,识别系统的构件及其交互关系,并且通过高层抽象或其他形式来展现目标系统的过程。