EagleBear2002 的博客

这里必须根绝一切犹豫,这里任何怯懦都无济于事

软件质量管理-05-质量管理

本文主要内容来自 SpriCoder 的博客,更换了更清晰的图片并根据新的课程设计做了补充和修正。

经典语录

People are happy to do it wrong and invest the time to fix it, which sometimes never works, as opposed to investing the time to get it right the first time.

—— Watts S. Humphrey

质量策略

质量概念

  1. 软件质量为“与软件产品满足规定的和隐含的需求能力有关的特征或者特性的全体”。[ANSI/IEEE STd 729]
  2. 软件质量为内外两部分的特性:其外部质量特性面向软件产品的最终用户,其内部质量特性则不直接面向最终用户。 《代码大全》
  3. 软件质量为软件产品可以改变世界,使世界更加美好的程度。从用户的角度考察软件质量,用户满意度是最为重要的判断标准。 [Tom Demarco]
  4. 软件质量为对人(用户)的价值。这一定义强调了质量的主观性,即对同一款软件而言,不同的用户对其质量有不同的体验。 [Gerald Weinberg]

面向用户的质量观

PSP 中也采用了面向用户的视图,定义质量为满足用户需求的程度。在这个定义中,就需要进一步明确:

  1. 用户究竟是谁?
  2. 用户需求的优先级是什么?
  3. 这种用户的优先级对软件产品的开发过程产生什么样的影响?
  4. 怎样来度量这种质量观下的质量水平?

典型用户质量期望

  1. 这款软件产品必须能够工作
  2. 这款软件产品最好有较快的执行速度
  3. 这款软件产品最好在安全性、保密性、可用性、可靠性、兼容性、可维护性、可移植性等方面表现优异;

个人软件过程(PSP)质量策略

  1. 用缺陷管理来替代质量管理;
  2. 高质量产品也就意味着要求组成软件产品的各个组件基本无缺陷;
  3. 各个组件的高质量是通过高质量评审来实现的;

不同缺陷消除方式消除缺陷的效率

测试消除缺陷的典型流程

  1. 发现待测程序的一个异常行为;
  2. 理解程序的工作方式;
  3. 调试程序,找出出错的位置,确定出错原因;
  4. 确定修改方案,修改缺陷;
  5. 回归测试,以确认修改有效;

评审发现缺陷典型流程

  1. 遵循评审者的逻辑来理解程序流程;
  2. 发现缺陷的同时,也知道了缺陷的位置和原因;
  3. 修正缺陷;
  4. 重要的缺陷关注:注入阶段、消除阶段和根本原因。

部分行业数据

资料来源 评审消除代价 测试消除代价 应用中消除缺陷代价
IBM [Remus and Ziles 1979] 1 4.1 倍于评审
JPL[Bush 1990] $90~$120 $10000
[Ackerman et al. 1989] 1 Hour 2~20 Hours
[Russell 1991] 1 Hour 2~4 Hours 33 Hours
[Shooman and Bolsky 1975] 0.6 Hour 3.05 Hours
[Weller 1993] 0.7 Hour 6 Hours

PSP 评审过程质量

  1. 评审检查表
  2. 质量控制指标
  3. 其他因素
    1. 环境
    2. 评审时机
    3. 个人评审和小组评审
    4. 缺陷预防
  4. 个人级别:单元测试和 code review,code review 优先
    1. 通过评审消除错误所需要的时间更少一些。
    2. 如果测试完成后再进行评审可能就没有那么认真进行评审。

评审的其他考虑因素

打印后评审往往效果更好:

  1. 单个屏幕可以展现的内容比较有限
  2. 评审人员的注意力

评审时机选择:编译(UT)之前 VS. 之后

个人评审和小组评审:

  1. 小组评审意义
  2. 先后顺序

质量指标

质量指标之一:Yield

Yield 指标用以度量每个阶段在消除缺陷方面的效率。

  1. Phase Yield = 100 \(\times\)(某阶段发现的缺陷个数)/(某阶段注入的缺陷个数+进入该阶段前遗留的缺陷个数)
  2. Process Yield = 100 \(\times\) (第一次编译前发现的缺陷个数)/(第一次编译前注入的缺陷个数);

只能预测,不能度量:因为无法得知注入的缺陷数目。

缺陷在开发过程中注入和消除的示意图

例子

  1. Yield 体现缺陷消除的效率问题
    1. 上游的问题可以引发更多的问题。
    2. 不能确定单元测试后是否有错误,不可知。
  2. IBM:最后的测试如果发现了一个错误,那么其中一定还有一个错误没有被发现(所以最后的 Yield 的值为 50),修改后如下(没有发现的也按照原本的比例来分)
阶段 注入缺陷数 消除缺陷数 遗留缺陷数 Yield(%)
设计 10 0 10 0
设计评审 0 4 6 40
编码 20 2 24 1/13  100
代码评审 0 12 12 50
单元测试 0 12 0 100

从上表估算后:

阶段 注入缺陷数 消除缺陷数 遗留缺陷数 Yield(%)
DFD 10+4 0 14 0
DFD REVIEW 0 4 10 2/7  100
CODING 20+8 2 36 2/19  100
CODE REVIEW 0 12 12 1/3  100
UNIT 0 12 12 50

估算交付物缺陷数——过程建模示例

质量指标之二:质检失效比 A/FR

A/FR = PSP 质检成本/PSP 失效成本,用来测量在第一次编译前花在查找缺陷上的时间的相对值。可用复查时间/(编译+测试)时间来计算。能很好地指示测试中发现缺陷的可能性。当 A/FR<1 时,程序测试一般会发现很多错误;当 A/FR>2 时,过程产生无缺陷的可能性更大。A/FR 的值对于小的独立的产品通常比 2.0 要大;A/FR 的值对于相对大的产品等于 1.0 较为合适。

A/FR 控制目标

  1. 理论上,A/FR 的值越大,往往意味着越高的质量。
  2. 过高的 A/FR 往往意味着做了过多的评审,反而会导致开发效率的下降。作为指南,在 PSP 中 A/FR 的期望值就是 2.0

质量指标之三:过程质量指标 PQI

5 个数据乘积:

  1. 设计质量:设计的时间应该大于编码的时间,\(\min\set{设计时间/编码时间, 1}\)
  2. 设计评审质量:设计评审的时间应该大于设计时间的 50%,\(\min\set{2 \times 设计评审时间 / 设计时间, 1}\)
  3. 代码评审质量:代码评审时间应该大于编码时间的 50%,\(\min\set{2 \times 代码评审时间/编码时间 , 1}\)
  4. 代码质量:代码的编译缺陷密度应当小于 10 个/千行,\(\min\set{20/(编译缺陷密度 + 10), 1}\)
  5. 程序质量:代码单元测试缺陷密度应当小于 5 个/千行 \(\min\set{10/(单元测试缺陷密度 + 5), 1}\)

PQI 越大,表示上面五个“应该”满足地越好,缺陷也就越少。PQI 超过 0.4 即可。

PQI 与交付后缺陷密度的关系

  1. PQI 与集成时缺陷数的关系

PQI 的作用:

  1. 判断模块质量
  2. 评估项目质量
  3. 为软件改进做依据

质量指标之四:Review Rate

  1. 评审的速度(Review Rate)是一个用以指导软件工程师开展有效评审的指标
  2. 高质量的评审需要软件工程师投入足够的时间进行评审
  3. 在 PSP 的实践中,代码评审速度小于 200 LOC/小时,文档评审速度小于 4 Page/小时

估算:

  1. 估算文档数量
  2. 估算代码数量
  3. 估算评审时间等等

质量指标之五:DRL

缺陷消除效率比度量的是不同缺陷消除手段消除缺陷的效率。

其计算方式是以某个测试阶段(一般为单元测试)每小时发现的缺陷数为基础,其他阶段每小时发现缺陷数与该测试阶段每小时发现的缺陷的比值就是 DRL。

阶段 缺陷个数/小时 DRL(UT)
设计评审 3.6 1.03
编码评审 8 2.29
单元测试 3.5 1

【2014】【2013】【2015A】质量路径 Quality Journey

为了追求极高的质量,你有哪些手段?

  • Step 1:各种测试
  • Step 2:进入测试之前的产物质量提升
  • Step 3:评审过程度量和稳定
  • Step 4:质量意识和主人翁态度
  • Step 5:个体 review 的度量和稳定
  • Step 6:诉诸设计
  • Step 7:缺陷预防
  • Step 8:用户质量观——其他质量属性

设计与质量的关系

  1. 低劣的设计是导致在软件开发中返工、不易维护以及用户不满的主要原因。
  2. 充分设计可以显著减少最终程序的规模,提升质量。(熟练的程序员每 10 行会注入一个错误)
  3. 设计本身也是一种排错的过程。

PSP 设计过程

设计什么?

  1. 设计目标程序在整个应用系统中的位置;
  2. 设计目标程序的使用方式;
  3. 设计目标程序与其他组件以及模块之间的关系;
  4. 设计目标程序外部可见的变量和方法;
  5. 设计目标程序内部运作机制;
  6. 设计目标程序内部静态逻辑;

设计的内容

动态信息 静态信息
外部信息 交互信息(服务、消息等) 功能(继承、类结构等)
内部信息 行为信息(状态机) 结构信息(属性、业务逻辑等)

PSP 设计模板

  1. 操作规格模板(Operational Specification Template, 简称 OST)
  2. 功能规格模板(Functional Specification Template, 简称 FST)
  3. 状态规格模板(State Specification Template,简称 SST)
  4. 逻辑规格模板(Logical Specification Template,简称 LST)

【2014】PSP 设计模板展现的信息

动态信息 静态信息
外部信息 OST/FST FST
内部信息 SST LST

OST

OST 描述的是系统与外界的交互,具体而言,是描述“用户”与待设计系统的正常情况和异常情况下的交互

OST 可以用来定义测试场景和测试用例,也可以作为和系统用户讨论需求的基础,特别是操作相关的需求描述。

FST

FST 描述的是系统对外的接口,这是一种静态信息的描述。

在 FST 中提供的典型信息包括类和继承关系,外部可见的属性和外部可见的方法等。

在使用 FST 模板的时候,消除二义性非常重要。因此,如果有可能,尽可能用形式化符号来描述方法等行为。

SST

SST 可以精确定义程序的所有的状态、状态之间的转换以及伴随着每次状态转换的动作。

在 SST 模板中,需要描述如下的信息:

  1. 所有状态的名称;
  2. 所有状态的简要描述;
  3. 在 SST 中需要使用的参数和方法的名称与描述;
  4. 状态转换的条件;
  5. 状态转换是发生的动作;

LST

LST 可以精确描述系统的内部静态逻辑。为了消除描述的二义性,一般建议用伪代码配合形式化符号来描述设计结果。

在 LST 模板中,需要描述如下的信息:

  1. 关键方法的静态逻辑;
  2. 方法的调用;
  3. 外部引用;
  4. 关键数据的类型和定义;

UML 常用图

  1. 用例图
  2. 时序图
  3. 类图
  4. 状态机图

UML 与 PSP 设计模板的关系

  1. UML 的用例图和时序图提供了与 PSP 中 OST 同样的信息;
  2. UML 中的时序图和类图所描述的类之间的关系以及对象之间的交互信息在 PSP4 个设计模板中没有对应的内容;
  3. UML 类图中记录了方法的型构,然而方法的行为没有描述,这一点在 PSP 的 FST 中有相应的内容;
  4. PSP 中的 LST 用以描述程序的静态逻辑,这在 UML 没有对应的图示方法;
  5. UML 中的状态图与 SST 描述的状态图类似,但是 SST 中描述的关于状态、状态转换条件以及状态转换中的动作没有对应的 UML 图示方法。

设计的层次

设计的层次:PSP 模板

设计验证方法

意义:简单评审不足以发现复杂缺陷

方法:

  • 状态机验证
  • 符号化执行验证
  • 执行表验证
  • 跟踪表验证
  • 正确性验证

状态机验证

正确状态机:

  • 完整
  • 正交

验证方法:

  1. 检验状态机,消除死循环和陷阱状态。
  2. 检查状态转换,验证完整性和正交性。
  3. 评价状态机,检验是否体现设计意图。

状态机示例

复杂条件组合

$$ A: ( ) n < n_{} / n := n + 1 \

B: / := \

C: n n_{} / := $$

真值表

条件 A 的体现

条件 B 和 C

符号化执行验证

符号化验证方法的基本思想是将描述设计的逻辑规格(一般用伪代码程序表示)用代数符号来表示,然后系统地开展分析和验证。具体步骤如下:

  1. 识别伪码程序中的关键变量;
  2. 将这些变量用代数符号表示,重写伪码程序;
  3. 分析伪码程序的行为。

符号化执行验证示例

1
2
3
4
5
begin
X:=X+Y;
Y:=X-Y;
X:=X-Y;
end
# 指令 X Y
初始值 A B
1 X:=X+Y; A+B
2 Y:=X-Y; A
3 X:=X-Y; B
结果 B A

优缺点分析

  1. 符号化验证的方法实施简单,可以给出一般化的验证结果,很多时候往往是唯一提供全面验证的方式。
  2. 这种方法通常用在验证一些复杂算法中,特别是对遗留系统的改造中,往往应用这种方法来识别和理解原有的设计。
  3. 但是这种验证方法不适用于有复杂逻辑的场合,而且,纯手工的验证方法也容易引入一些人为的错误。

执行表验证

执行表用一种有序的方法来跟踪伪码程序的执行状况,分析程序行为,从而验证设计。具体步骤如下:

  1. 识别伪码程序的关键变量;
  2. 构建表格,表格左侧填入主要程序步骤,右侧填入关键变量;
  3. 初始化被选定的变量;
  4. 跟踪被选择的关键变量的变化情况,从而判断程序行为。

执行表示例

跟踪表验证

跟踪表验证方法是对执行表验证方法的一种扩充。具体步骤如下:

  1. 识别伪码程序的关键变量;
  2. 构建表格,表格左侧填入主要程序步骤,右侧填入关键变量;
  3. 初始化被选定的变量;
  4. 识别将伪码程序符号化的机会,并加以符号化;
  5. 定义并且优化用例组合;
  6. 跟踪被选择的关键变量的变化情况,从而判断程序行为。

识别符号化机会

例如,令 p = 左侧空格数;q = 非空字符数;Length = 字符串长度

正确性检验

正确性检验将伪码程序当成数学定理,采用形式化方法加以推理和验证。这种方法的步骤如下:

  1. 分析和识别用例;
  2. 对于复杂伪码程序的结构,应用正确性检验的标准问题逐项加以验证;
  3. 对于不能明确判断的复杂程序结构,使用跟踪表等辅助验证。

While-Do

典型 while 循环如下:

1
2
3
4
while(condition)
begin
states;
end

一个正确的 while 循环设计应当满足如下条件:

  1. condition 是否最终一定会为“假”,从而使得循环可以结束;
  2. condition 为“真”的时候,单独的循环结构执行结果与循环体再加一个循环结构,其执行结果是否一致?
  3. condition 为“假”的时候,循环体内所有变量是否未被修改?