测试运行

使用 PERIL 分析项目危害和风险

James McCaffrey 博士

代码下载位置:MSDN 代码库
在线浏览代码

目录

元风险
风险识别
风险分析
总结

所有的软件项目都会面临风险。风险是可导致某种损失的事件,其发生具有不确定性。风险与软件测试之间的关系非常简单。您通常无法全面地测试某个软件系统,而风险分析可找出那些能导致最大损失的问题。您可以借助此信息划分测试工作的优先次序。在本月专栏中,我介绍了一些可用于找出和分析软件项目风险的实用技术。现在请随我来。

假定您正在开发某种基于 ASP.NET Web 的应用程序。图 1 显示了一些与软件风险分析有关的重要概念和问题。风险分析的整个过程包括找出风险、估计发生每种风险的可能性、确定与每种风险相关的损失,将可能性与损失信息组合为一个称为风险危害的值。

fig01.gif

根据图 1 中的示例数据,风险“User IDs can be viewed”(可查看用户 ID)的风险危害最高,其余因素平齐,您很可能希望使其具有最高的测试优先级以防止实际发生该风险。但是如何找出风险呢?如何估计出现风险的可能性和损失呢?如果无法估计出发生风险的可能性和损失还可以进行风险分析吗?

尽管为正式化和标准化风险分析术语已做过很多努力,但在实际中不同的术语仍趋向于在不同的问题领域中使用。我将使用术语“风险分析”来表示将风险可能性乘以风险损失以计算风险危害,或表示找出、分析和管理软件项目风险的整个过程。

虽然风险分析在软件开发中极为重要,但据我所知,很多风险分析技术在软件测试社区中并非人人皆知。如果搜索 Web,您会发现成千上万个有关软件风险分析的参考。但这些参考的绝大多数只是侧重高层次的风险分析而不提供实用技术,或者仅提供某个特定的风险分析技术且不解释该技术如何应用到整个风险分析框架中。我将向您介绍风险分析的概述以及一些可立即在软件开发环境中使用的实用技术。

在本专栏章节中,我将介绍两种所有软件项目中都很常见的元风险。然后向您介绍三种找出软件项目相关特定风险的方法和三种分析风险的方法。我还将向您特别介绍一种有趣的新风险分析技术,名为“使用分级影响和可能性的项目风险危害 (Project Exposure using Ranked Impact and Likelihood, PERIL)”,该技术在软件开发环境中尤为有用。最后将对风险管理进行简要的总结。我相信这里提供的技术对软件测试、开发和管理工具包都极具价值。

元风险

我将两种特殊类型的软件项目风险分析称之为时间和成本元风险分析。传统项目管理所定义的概念有不同的名称,分别是“项目管理三重制约”和“项目管理三要素”。简言之,就是每个项目实际上都具有三个约束因素:成本、进度和范围。成本是项目必须的花费,进度是完成项目所必需的时间,而范围是必需的项目功能及其质量。

这三个项目约束有很多其他别名。例如,成本也被称为预算或资金。进度通常称为时间或持续时间。范围有时称为功能或质量,或者“功能/质量”。请注意,实际上通常可将这个“功能/质量”约束认为两种不同的约束。

这些约束中的任何一个发生变化都很可能引起其他的一个或两个约束发生变化,这是它的重要特征。例如,如果您正在开发某个软件应用程序,但突然需要提前完成该项目,您可能需要增加资金投入(例如购买额外的资源或外包部分项目)或削减某些功能或质量。如果削减项目预算,很可能需要更长时间完成项目,删除某些功能或降低项目的质量。使用项目管理三要素模式,由于软件测试旨在改进系统的质量,所以软件项目中两个最高级别的风险是未按时完成项目和项目超出预算。

有个相对简单但行之有效的方法可以估计软件项目的整体进度和成本风险。我们来看一下时间/进度元风险(以相同方式对预算/成本风险进行分析)。高层元风险分析的第一个步骤是将整体项目分解为更易管理的小活动块。

例如,假设您正在处理某个小型的 Web 应用程序项目,而该项目必须在 30 个工作日内完成。元风险分析的第一步是列出该项目中的所有活动。 这里最常见的办法是创建一个工作分解结构 (WBS),如图 2 所示。创建一个包含整个项目的顶层任务。然后将该任务分解为多个更小的子任务,通常约三到七个任务。重复该过程,将每个子任务分解为更小的子任务,直至达到环境所需的精细度。

fig02.gif

图 2 工作分解结构

最下层的叶节点任务有时被称作工作包。任务的分解方式和 WBS 的细化程度取决于很多因素。例如,在较为灵活的开发环境中,可能简单的双层工作分解结构即能满足您的需求。如果您使用传统的软件开发生命周期方法分解某个极为庞大的复杂软件项目,您可能会有成千上万个工作包。

您可以使用常用的高效工具(如 Microsoft Office Excel)或使用较为复杂的工具(如 Microsoft Office Project)手动创建一个较小的 WBS。WBS 不包含排序、时间或成本信息。换言之,WBS 可告知您必须完成什么任务,但不会透露它们的顺序,也不会告知每个任务所花费的时间或成本。通常,创建完工作分解结构后,接下来要使用工作包创建一个先后次序图表。

fig03.gif

图 3 先后次序图表

fig04.gif

先后次序图表可添加排序信息。图 3 所示的图表指明“Requirements”(要求)任务必须先于“Database Back End”(数据库后端)任务完成,而“Database Back End”(数据库后端)任务必须在“Middle-Tier”(中间层)任务和“Front-End”(前端)任务开始前结束。依照该先后次序图,后两个任务可并行执行。最后,“Middle-Tier”(中间层)任务和“Front-End”(前端)任务必须在“Deploy Application”(部署应用程序)任务开始前结束。

创建含有其排序信息的先后次序图表后,时间元风险分析接下来会估计各个工作包所需的时间。尽管您可以将每个时间视为单个数据点估计,但更好的方法是提供三种估计值—乐观估计值、最佳猜测值和悲观估计值。

那么,如何取得这些估计值呢?迄今为止,确定时间和成本估计值是软件项目元风险分析中最困难的部分。估计活动时间和成本有多种方法。您可以使用历史经验、有根据的猜测以及复杂的数学模型等。具体使用哪种技术视您的情形而定。无论使用何种方法,估计一组小活动的时间和成本要比估计一个庞大活动的时间和成本要轻松许多。图 4 中的表格显示了时间风险元分析示例。

在分析乐观、最佳猜测和悲观时间数据时,通常会使用一种称为 Beta 分布的简单数学分布。Beta 分布的平均数计算方法如下:

(optimistic + (4 * best-guess) + pessimistic) / 6 

因此,对于“Deploy Application”(部署应用程序)任务,其平均完成估计时间为:

mean = (3 + 4*8 + 13) / 6
     = 48 / 6
     = 8.0 days.

请注意,Beta 平均数是用权数 1、4 和 1 求得的加权均值。因此,Beta 分布的方差由此公式指定:

((pessimistic - optimistic)/6)²

所以,“Deploy Application”(部署应用程序)任务的方差为:

variance = ((13 - 3) / 6)²
         = (10/6)²
         = (1.6667)²
         = 2.78 days²

该项目的整体标准偏差是活动方差之和的平方根。因而在此示例中,方程式如下所示:

std. deviation = sqrt(5.44 + 1.78 + 2.25 + 2.78)
               = sqrt(12.25)
               = 3.50 days

请注意,该计算并不使用“Design and Code Logic Middle-Tier”(设计和代码逻辑中间层)活动的数据。由于“Logic Middle-Tier”(逻辑中间层)活动可与“Database Back-End”(数据库后端)活动并行执行,而“Front-End”(前端)活动只有在这两个并行活动结束后才能开始,因此较短的并行活动 (Logic Middle-Tier) 无法显式计入完成该项目的总时间。

这种分析被称为关键路径法 (CPM),它是一项标准项目管理技术。计算出进度均值和方差数据后,就可以计算出完成整个项目花费 30 天以上时间的概率:

z = (30.00 - 28.83) / 3.50 = 0.33
p(0.33) = 0.6293
p(late) = 1.0000 - 0.6293 = 0.3707

首先计算所谓的 z 值,该值的计算方法是将计划完成该项目的时间量(本示例为 30 天)减去估计完成时间(28.83 天),然后除总的任务标准偏差(3.5 天)。得到 z 值 (0.33),然后在标准正态分布表中查找相应的 p 值或使用 Excel NORMSDIST 函数 (0.6293)。最后,从 1.0000 中减去 p 值即可得到项目超出时间表的概率。

如果您仅关注能否超出预计时间而不关注能否提前完成,那么您执行的只是一个单侧分析。在此示例数据中,花费 30 天以上完成 Web 应用程序的概率为 0.3707,或近 40%——这个情况极具风险。对这一结果进行分析可以挖掘有帮助的信息。原先计划的 26 天的开发进度过于接近该项目 30 天的完成限制,这样一来可能没有充足的机动时间来应对进度偏差。

显然,在本示例中,您的元风险结果完全取决于输入数据(时间估计值)的质量。如果输入估计值不正确,任何统计学分析都无法得出有意义的结果。您可以使用上述技术来计算项目超出预算的元风险概率。在得出项目超出预算的元风险概率后,如果能估计出由于推迟导致的资金损失,那么您就可以计算出元风险的风险危害。

有时您可能需要根据合同创建软件系统,而合同中已明确规定了数目巨大的滞纳金。例如,假设您的合同规定如发生延迟交付会有 10,000.00 美元的罚金。则您的元风险危害为 $10,000.00 * 0.3707 = 3,707 美元。有时,延迟交付的软件项目成本是“非常非常昂贵”的,很难给出具体的估计值。

但请注意,即使没有计算风险危害,您的时间元风险分析也会给出有用的信息。请查看图 4 中的数据,您会看到“Determine Requirements”(确定要求)任务的进度方差最大。因此,只需尽早增加资源即可减小任务方差,进而可降低超出进度的概率。

风险识别

时间和成本元风险可通过将任务反复分解为较小的子任务来逐步确定风险事件(尽管并不容易),但一般情况下,风险识别要复杂得多。在软件开发和测试环境中,有三种主要风险识别方法:基于分类、基于方案和基于规范。

分类法就是一个分类列表。请看下面的假设。您正计划一次乘飞机旅行,使用了一个每次旅行前都会使用的标准提醒列表。其中包含诸如“我拿身份证了吗?”和“是否检查航班有无延误?”之类的陈述和问题。

多年来,很多人和公司都已创建了软件风险分类法。Barry Boehm 就创建了这样的一个列表,他是软件项目风险领域的先驱和知名研究人员。1989 年,Boehm 确定了十大软件风险分类法并于 1995 年更新了该列表。以下列出了 1995 年的十大软件项目风险分类法:

  1. 个人错误
  2. 进度、预算、流程
  3. 商用成品软件、外部组件
  4. 要求失配
  5. 用户界面失配
  6. 体系结构、性能、质量
  7. 要求变更
  8. 旧版软件
  9. 外部执行的任务
  10. 应变计算机科学

您应清楚 Boehm 的十大风险列表不能直接确定风险。分类只不过是为您提供了思考软件项目所含风险的起点。例如,第一个风险“个人错误”包括许多与人员有关且各不相同的可能风险。您的项目可能缺乏足够的工程师来创建应用程序或系统。或起关键作用的工程师在项目中途离开。也可能是工程人员的技能无法达到项目的需求。其他在此就不一一列举了。

除第十类风险“应变计算机科学”外,其他大多数您应当都很熟悉。它在某种程度上是一个全能类别,包括与事情相关的多个任务,如技术分析、成本效益分析和原型构建。

另一个常用软件风险分类列表是由软件工程学院 (SEI) 创建的。SEI 是美国联邦政府资助的 36 个研究开发中心之一。这些研究中心是个怪异的混合体,由公款资助,却出售产品和服务。SEI 软件风险分类法创建于 1993 年,其中包含约 200 个问题。例如,问题 1 为“这些要求稳定吗?如果不是的话会对系统(质量、功能、进度、集成、设计和测试)有何影响?”问题 16 为“如何确定算法及设计(原型构建、建模、分析和模拟)的可行性?”您可以从该文档附录中找到 SEI 风险分类法

在基于方案的软件风险识别中,您可以将自己想像成多种角色,为这些角色创建方案并找出各个方案中可能出现的错误。还是以先前所述的飞机旅行为例,您可能想跟踪旅行中的各个步骤。例如,“首先要驾车去机场。接着停好车。然后在机场柜台办理登机手续。”此方案可能包含很多风险,包括由于道路施工或交通事故导致的晚点、无停车位、忘带证件等。

在软件项目环境中,基于方案的风险识别经常用到用户、开发人员、测试人员、销售人员、软件架构师和项目经理这些角色。用户方案可能是“首先要安装应用程序。然后启动该应用程序。”风险识别方案经常能直接映射为某个测试案例。

基于方案的风险识别中,角色不一定必须是人。也可以是软件模块或子系统。例如,假设您有一些执行加密和解密任务的 C# 对象。您可以想象该对象就是角色并创建方案,如“首先要接受一些输入并实例化自身。接下来接受一些输入并将其传给我的加密方法。”与基于分类法的识别相比,对基于方案的软件风险识别的研究要少很多。软件项目的风险识别模式中的研究论文对该领域进行了很好的介绍,并提出了一个基于模式的有趣理论方法。

除上述两种风险识别策略外,第三种方法是基于规范的策略。通过此方法可以仔细检查产品或系统规范文档中的每种功能和流程,并尝试找出可能出现的错误。在飞机旅行这一示例中,您可以仔细检查旅行代理商制订的详细行程。假设某个 Web 应用程序的规范文档指出您计划使用外部承包商来生成该应用程序的各种“帮助”文件。外部项目依赖关系会新增很多风险。如果承包商无法按时交付怎么办?如果承包商的工作质量无法达到您的主观标准怎么办?

实际中并不存在一个最佳风险识别策略,因为每种策略都各有优缺点。一开始识别软件项目中的风险时,适合使用风险分类法。该方法让人感觉略为呆板,因为您要一一检查分类法中的每个问题或每项陈述。通过为不同的人员分配不同的分类法问题,分类法还可帮助实现多人协同找出风险。缺点是该方法极为耗时。同时,分类法本质上是种通用的方法,它们无法找出软件系统特有的风险,需要您通过其他途径识别这类风险。

与基于分类法的风险识别相比,基于方案方法的优势在于针对性较强,可促使您从具体之处着手。另一方面,基于方案的风险识别技巧性更强,很容易让您为之着迷。基于规范的风险识别通常是针对性最强且最为特殊的方法。但它的结果质量取决于您的规范文档。如能将这三种方法综合起来使用,您就可以更准确地找出软件风险。

风险分析

风险分析是将某个风险事件的概率(可能性)与该事件导致的资金损失(或负面影响)相结合的过程,它的结果用于与其他风险做对比并确定风险的优先级。在本节中,我将介绍两种较旧的风险分析方法(预期值技术和分类技术),以及一种名为 PERIL 的新方法。我们首先来了解预期值技术。

请看图 5 中的示例。假设您已经找出了四个风险事件。我们分别称它们为风险 A、风险 B、风险 C 和风险 D。然后将概率分配给各个风险事件。概率是一个介于 0.00(表示不可能发生)与 1.00(表示肯定发生)之间的数字,用于表示事件发生的可能性。接下来,将资金损失值分配给各风险事件,这是风险事件发生时您的损失。此时,只需将各风险事件相应的风险概率乘以该风险的损失即可得到风险危害。

fig06.gif

使用此方法,风险危害只是预期值的一种形式。显然,预期值方法存在一些主要问题。如何估计风险概率?如何估计风险损失?在某些情况下您可以根据良好的历史数据或经验进行估计,但创建软件时这种情况通常比较少见。根据个人经验,风险分析的预期值方法在软件开发环境中通常并不适用。

因为在很多软件开发环境中很难或几乎不可能估计某个风险事件概率或其关联损失,常用的对策是对风险概率和风险损失使用类别尺度。这就是分类技术。示例可以更好说明这一点。假设您已找出四个风险 A、B、C 和 D。利用此方法无需猜测每个风险的概率和损失,您可以生成一个分类风险危害表,如图 6 顶部所示。

fig06.gif

如您所见,我总共有九种风险危害。有三种风险概率——低、中和高。有三种损失——也是低、中和高。概率分类和损失分类的叉积得到九种风险危害,从低-低(低概率、低损失)到高-高(高概率、高损失)。现在观察四个风险事件,向每个事件分配一个低、中或高概率,然后再分配一个低、中或高损失,产生一个九点风险危害。它的思路是分配概率值“低”通常比分配某个准确的数值(如 0.5)更为合理。

图 6 底部表格中的假想数据表明风险 B 的危害级别最高,与危害级别最低的风险 A 相比,需要更多关注或资源(包括测试)。尽管分类风险分析方法一定程度上缓解了难于或无法确定概率和损失的问题,但该技术也引发了一些新问题。

请注意,我对概率和损失都任意使用了三个分类。这种方法极为粗糙。假设为提高风险分析精度,我决定对概率因素和损失因素都使用五个分类:极低、低、中、高和极高。这样我总共有 25 个风险危害分类——(极低 + 极低)到(极高 + 极高)。那么,如何评定或比较这 25 个危害值呢?如何将(极低 + 高)风险危害与(高 + 中)危害进行比较呢?如果有很多人都在评估您的分类风险危害数据,他们会以相同方式理解危害数据吗?

为了专门解决这类问题,我在多年前开发了一项名为“使用分级影响和可能性的项目风险危害 (PERIL)”的技术。其思路核心是使用分类(与在分类方法中相同),但将它们转换为量化尺度,以便将它们轻松地组合起来生成数字危害度量值。

下面来看一个示例。假设您已经找出了四个风险:A、B、C 和 D。现在假设您确定将有含义的数字分配给每个风险的概率和损失不可行。另外,您发现自己所在的具体环境适合将风险概率分为五类:极低、低、中、高和极高。接下来,您决定将损失/影响分为四类:极低、低、高和极高。PERIL 技术利用一个名为“排序次序重心法”(rank order centroid) 的简单数学构造将分类数据映射成量化尺度。示例很好地解释了映射技术。与五种概率尺度相对应的五个排序次序重心映射如图 7 所示。

同样,四类影响映射已计算完成,如图 8 所示。现在将每个风险的概率和影响质心值相乘,计算该风险的危害值。例如,请参考图 9。这里风险 D 的概率级别为高,其映射值为 0.25667;影响级别为低,其映射值为 0.14583,因而其危害值为 0.25667 * 0.14583 = 0.03743。由此数据可推断出风险 C 的危害值显然最高,需要注意防范风险,并为出现风险创建应急计划。

fig07.gif

无需再分别计算每个风险的危害值,可构建一个完整的 PERIL 危害值查询表格(包括五个概率级别和四个影响级别),然后只需从 PERIL 表中读取危害值即可,如图 10 所示。PERIL 技术可普及为任意数量的概率和影响类别。

fig10.gif

排序次序重心将等级(如第一、第二和第三)映射为数值(如 0.61111、0.27778、0.11111)。请注意,排序次序重心之和趋向为 1.0(有取舍误差)。在西格马 (∑) 符号表示法中,如果 N 为类别数,则与第 k 个类别对应的数值为:

inline.equation.gif

类别与数值之间有许多其他的数学映射,但有关研究表明使用排序次序重心法是映射级别(如在风险分析中所使用的示例)的一种很好的办法。本专栏不详细讨论排序次序重心,但可做些非正式的讲解。假设您只处理两类风险事件概率:高和低。若假定高风险事件可能性的概率大于 0.5,则低风险事件可能性的概率就小于 0.5。无需其他信息即可认为高风险事件的可能性介于 0.5 和 1.0 之间,因而等于 0.75。同样地,低风险事件的可能性介于 0.0 和 0.5 之间,即 0.25。0.75 和 0.25 这两个值就是 N = 2 个分类时的排序次序重心(如图 11所示)。

fig11.gif

请注意,在使用 PERIL 时,我使用的术语为可能性和影响,而不是概率和损失。PERIL 可能性和影响是相对的标准化值。即使 PERIL 可能性与概率集类似,值之和趋向为 1.0,需要强调的是 PERIL 可能性值并不是概率。同样,PERIL 影响值仅在彼此相比较时才有意义,而非资金损失值。

这三项用于确定风险危害的技术——预期值技术、分类技术和 PERIL 技术各有其优缺点。如果每个风险事件都有足够的历史数据来估计其概率和相关的资金损失,则预期值技术通常是最佳选择。但在软件开发和测试环境中,很少能有足够的数据供您做出有意义的概率和损失估计。

在另一种极端情况下,如果实际上没有任何的历史风险数据,则最适合有两或三种风险概率类别和相关风险损失的分类技术。如果能将风险事件可能性和关联的风险影响(可以是资金或非资金损失,如士气影响)大致分类为五个类别,则 PERIL 技术通常是您的最佳选择。

无论您决定在环境中采用哪种风险分析技术,都必须慎重地解释您的结果。请牢记在输入估计中,风险分析经常变数最大。换言之,风险分析仅仅是为软件测试工作排定次序提供指导方针,而不是规则。

风险资源

有关风险的详细信息,请参阅以下《MSDN 杂志》**专栏:

测试运行:使用 MAGIQ 进行竞争分析

测试运行:层次分析法

总结

在本专栏中,我还未讨论风险分析整体过程中的风险管理。风险管理涉及多项活动,例如建立输入和存储风险数据的系统,以及随软件项目监控风险信息。风险管理系统有多种形式:从基于电子邮件的日常系统到基于 Excel 电子表格的轻型方法,直至基于使用 Microsoft Team Foundation Server 系统中风险项的复杂方法。

无论您决定如何管理风险工作,都要了解风险分析是一个持续反复的过程,这一点很重要。由于软件项目开发是个动态的活动,因此您必须随项目的发展修订风险数据和结果。

从常识来看,风险分析应成为所有软件项目的重要组成部分。从只有一个开发人员,工作量很小的项目,到数百甚至数千名开发人员参与的大型常年项目,都应进行某些风险分析。但有相当数量的调查表明很多软件并不进行风险分析,特别是一些中小型软件项目。

原因可能有几种。我猜测之所以很少执行风险分析的一个原因是因为它们需要技术和智力投入,而这些与编码所需的技能和智力投入几乎是截然不同的。我来做个解释。大多数软件开发活动是基于某个封闭系统相对明确定义的,它们面向宏观目标,通常会提供即时反馈。例如,当您作为开发人员编写代码时,可以在编译和执行代码时获得即时的反馈。如果代码按预期效果运行,您通常就会得到某种程度的满足。而执行软件风险分析却是项非常困难的活动。您不会得到任何类型的反馈,也不会得到过去曾有的成就感。

依我看来,软件风险分析与编码完全不同。希望本专栏能让您了解到执行风险分析的重要意义,并为您提供了货真价实的技术,能帮您创建质量更高且更可靠的软件。

请将您想向 James 询问的问题和提出的意见发送至 testrun@microsoft.com

James McCaffrey 博士供职于 Volt Information Sciences, Inc.,负责对华盛顿州雷蒙德市 Microsoft 总部园区内工作的软件工程师的技术培训进行管理。他参与过多项 Microsoft 产品的研发工作,其中包括 Internet Explorer 和 MSN Search,是<em></em>《.NET 软件测试自动化之道:一个问题解决方案的方法》(Apress,2006)一书的作者。您可以通过电子邮件 jmccaffrey@volt.comv-jammc@microsoft.com 与他联系。