疑问
最近我在做售前,需要对项目进行RAID分析,以便根据合理的假设和风险给出合理的报价。我对RAID有一定了解,日常工作中常涉及假设、依赖、风险和问题。然而,实际分析中,我常有以下疑问:
- 假设和风险的区别是什么?
- 假设和依赖的区别是什么?
- 假设必须在它成为假设之前得到证明么?如果我们不能证明一个陈述是真的或假的,就不能把它作为假设么?在一个事件没有发生之前,我们怎么证明它肯定会或不会发生呢?
- 风险必须在它成为风险之前得到证明么?如果我们不能证明一个陈述有风险,就不能把它作为风险么?风险的标准是什么?
- 如果目前没有足够的信息证明一个陈述是对的或错的,我们该如何处理?
- 提出风险就必须同时提出解决方案么?对于目前没有解决方案的风险,我们该如何处理?
我将试着在本文中解答这些疑问。为了表达方便,我在文中有时会用事件来表述RAID,有时会用陈述来表述RAID,如果造成困扰,还请谅解。
什么是RAID?
在开始讨论之前,我需要先澄清一下我所说的RAID是什么。它是四个单词的缩写,有的人说是Risks,Assumptions,Issues和Dependencies,也有的人说是Risks,Actions, Issues和Decisions。这里我采用的是第一种说法,RAID表示Risks,Assumptions,Issues和Dependencies。
让我们先来看看DeepSeek对RAID的解释:
DeepSeek的解释和我的理解是一致的,如果是一个人做RAID分析并没有什么问题,按照自己的理解分析就好了。但在面对一个真实的项目时,特别是当团队无法达成一致时,上述定义就会带来我在文章开头所提出的疑问。
例如,对于陈述“客户自己负责软件测试,我们不需要提供测试人员”。有的团队成员觉得它是真的,是一个假设,因为这是客户的要求。有的团队成员觉得它是假的,是相反的假设,因为从历史经验看客户的测试能力和资源都不足。有的团队成员觉得它不是假设,是依赖,因为它不在我们的控制范围内。还有的团队成员觉得它是风险,因为客户有可能为我们提供额外的测试资源,但也有可能和以前一样。
面对这些争论,我们该如何达成一致呢?有没有什么准则可供参考呢?
重新定义RAID
为了更好的理解RAID,我用认知状态-主观确定度两个维度重新对其进行了定义。
维度
横坐标 - 认知状态
横坐标指的是我们对事件的认知状态。对事件了解的越少,印象越浅,我们越不容易意识到该事件的存在,我们完全无法意识到的事件就是我们不知道的事件。对事件了解的越多,印象越深,我们越容易意识到该事件的存在,我们清楚意识到的事件就是我们知道的事件。
注意,这里的认知状态是指我们进行RAID分析时那一刻的认知状态,是瞬时状态,而非最终状态。例如,在第一次RAID分析时我们可能没有意识到和测试相关的事件,在那一刻,我们对测试相关的事件处于不知道的状态,是瞬时状态。但在下一次RAID分析时我们就想起来了,从最终结果看我们对测试相关的事件处于知道的状态,是最终状态。
简单来说,横坐标的认知状态代表着我们在进行RAID分析时能否能够猜想到某个事件。
纵坐标 - 主观确定度
纵坐标指的是我们对事件在未来是否会发生的主观确定度。这需要我们根据自身经验来判断其发生的概率,发生的概率越大或越小确定度就越高,否则就越低。
注意,我们要把事件的不确定性和由事件引起的损失的不确定性区分开。损失的不确定性往往是由事件的不确定性引起的,在一定范围内,只要我们能够确定与损失有关的事件会或不会发生,就能够确定损失的大小,损失的不确定性也就自然而然地消失了。如果我们不确定损失,那一定是有某些事件我们不确定其是否会发生。所以,我们在这里只考虑事件的不确定性。
象限
问题(Issues)
我们一般把问题定义为通过努力获得的结果(现状)与期望的结果(目标)之间的差距。这里,我们把问题等同于引起问题的事件。
问题的定义比较特别,它的两个维度不在同一个时间范围内。认知状态是指问题发生之前的认知状态,很明显,在问题发生之前我们是不知道它的存在的。主观确定度是指问题发生之后的主观确定度,并不是所有的问题在发生之后我们都能确定它是否还会再发生。所以,问题横跨了不知道-确定和不知道-不确定两个象限。
先举一个不知道-不确定的例子。我的团队曾经有一个在AWS上稳定运行了三年的系统,有一天它突然出现了所在AWS区域(AWS Region)无法使用的问题,在该问题出现之前我们并不知道AWS会出现整个区域无法使用的情况,现在即便知道了,我们也不确定这种情况发生的概率有多大。
再举一个不知道-确定的例子。我们在修改代码后都要执行单元测试,有时会出现了看似不相关的失败用例,在其出现之前我们并不知道这些测试用例会失败,但当我们知道并修复后,我们就很确定这些测试用例不会再失败。
假设(Assumptions)/依赖(Dependencies)
我把假设和依赖放在了同一个象限。它们都是我们知道且确定的事件,我们可以说服他人相信它们会发生或不会发生。我们所有的计划和行动都是基于假设和依赖做出的,假设和依赖是否正确决定了我们计划和行动的成败。
注意,确定和正确是不同的,确定是我们的主观判断,确定的不一定是正确的,是否正确只有在我们执行完计划和行动之后才知道。
假设和依赖的不同点是依赖不在我们的负责范围或控制范围内,我们无法通过改变依赖本身来增加确定度,只能被动接受或间接影响其代表的事件,通过改变自己来增加确定度。
先举一个依赖的例子,我的团队有一个项目依赖于Zuora进行订阅管理。我们很容易能知道Zuora是一个成熟的订阅方案提供商,而且我们很确定它在未来也会提供稳定专业的服务。但Zuora不在我们的控制范围内,即便未来我们不再确定它是稳定的,我们也无法通过改变它来增加确定度,只能被动接受,并通过改变自己来增加确定度。例如,当Zuora通知我们需要定期暂停服务以进行维护时,我们无法改变这一安排,只能通过调整业务逻辑来尽量减少停机带来的损失。
再举一个假设的例子,一般项目都会假设我们有充足的办公资源。我们很容易能知道办公资源是充足的,而且我们很确定它在未来是成立的。即便我们不再确定它是成立的,我们也可以通过购置办公资源等手段来增加确定度。
风险(Risks)
风险是我们知道但不确定的事件,我们无法说服他人相信它们会发生或不会发生。我们无法基于风险确定我们的下一步行动,必须先增加其确定度。
对于前端团队,一个常见的风险是后端提供联调的API有可能延期交付。根据现有信息,有的团队成员认为我们应该继续等待API进行联调,避免做无用功。有的团队成员认为我们应该先自己模拟API进行自测,避免错过产品交付日期。除非有更多的信息让我们相信API能在某个日期交付,即增加该事件的确定度,否则我们很难决定团队下一步该怎么做。
RAID的象限转换
在整个项目存续期间,随着已发生的事件越来越多,可获取的信息越来越多,我们知道的事件会越来越多,对已经知道的事件的确定度也会逐渐变化,这就造成了事件会在各个象限之间进行转换。同时,这也意味着RAID分析不能只进行一次,而是要重复进行。
在上图中,除了上节介绍的RAID,我还额外添加了经验。它是一个广义的经验,泛指团队从历史事件中学习到的经验教训,团队的工作流程和团队成员的能力等要素。
状态转换
猜想:将经验转换为假设/依赖
虽然我们无法知道所有未来的事件,但我们可以凭借经验进行猜想,经验越丰富,能够猜想出的未来的事件就越多,这些猜想出的事件就是假设或依赖。团队中常见的进行猜想的机制有头脑风暴,Project Inception等。
你可能会有这样的疑问,我有时猜想出的事件本来就是不确定的,为什么不直接将其设置为风险呢?原因是团队中每个人对同一事件的确定度是不一样的,我们有可能被他人说服,从而提升对该事件的确定度。先将猜想出的事件作为假设或依赖可以更好的促进这种讨论,保证假设或依赖的正确性。
我们可以借用项目管理三角形中的概念,从项目的时间、范围和成本三个方面来猜想团队需要关注的假设和依赖。
首先,所有确定的时间节点都是我们需要关注的假设或依赖,例如,联调日期,验收日期,上线日期等,它们往往以项目路线图(Roadmap)的形式存在。在如今盛行的DDD(Deadline Driven Development,最后期限驱动开发)开发模式下,错过时间节点会涉及大量的跨团队沟通,甚至有可能影响整个项目计划。
其次,所有确定的需求都是我们需要关注的假设或依赖,例如,确定的功能需求和跨功能需求,它们往往以用户故事(User Story)或验收测试条件(Acceptance Criteria)等形式存在。这些确定的需求是团队的交付内容,其正确性直接决定项目成败。
然后,确定的团队结构,软件开发生命周期(SDLC)实践,系统架构,基础设施等也是我们需要关注的假设或依赖。我们需要有一个结构合理的团队,在经济的基础设施上,通过合理的系统架构设计和先进的SDLC实践,来实现确定的需求。不合理的团队结构会直接增加项目的人力成本,例如,我们可能并不需要那么多的高级开发人员,初级开发人员可以完成大部分需求。基础设施的选择会直接影响软件的运行成本,例如,我们可能并不需要维护自己的机房,云服务可能更划算。不合理的系统架构设计会增加软件的维护成本,例如,在业务简单的情况下,采用单体架构可能更容易维护。不成熟的SDLC实践会增加项目的隐性成本,例如,自动化测试的缺失会导致测试成本的增加。
最后,所有假设或依赖都需要经过讨论。如果一个假设或依赖没有任何人提起过,或有人提起后所有人都立即一致确定它是成立或不成立的,那么它就不是一个我们现在需要关注的假设或依赖。我们需要关注的假设或依赖是那些某些团队成员不太确定却又被其它成员说服的假设或依赖。例如,当有人提出团队将采用敏捷开发时,所有人都认为是成立的,那我们就不必再关注这条假设了,它已经是所有团队成员的默认假设,不需要团队再付出额外的精力来关注它。
前置反馈循环
我将下面两种状态转换的组合称为前置反馈循环,因为它可以在问题出现之前减少问题,是我们进行项目风险管理的主要手段。
收集反驳信息:将假设/依赖转换为风险
在得知某些信息后,如果我们不再确定当前的假设或依赖是成立的,那么这些信息就是当前假设或依赖的反驳信息。收集反驳信息的过程就是降低假设或依赖的确定度的过程。项目中常见的收集反驳信息的机制有每日站会,故事卡 Kick off 和 Desk check,Threat Modeling,POC(Proof of Concept),Code Review,测试等。
我们是依据某一刻的有限信息依靠经验猜想出的假设或依赖,随着时间的推移,我们获取的信息越来越多,我们对某些假设或依赖的确定度会降低,从而将它们识别为风险。这种确定度的降低并没有给项目带来实际的损失,是一种我们期望看到的变化,因为这可以让我们有机会在它们造成损失之前寻找解决方案。
例如,在项目开始时,根据以往合作的经验,我们依赖于后端团队能够按时交付API进行联调。但当我们得知该团队出现了较大的人员调整后,我们会觉得API的交付可能会延期,我们便会将其识别为风险并开始寻找解决方案,例如通过模拟API进行联调。
规避风险:将风险转换为假设/依赖
风险的特点就是确定度低,而我们要做的就是增加它的确定度,将其转变为假设或依赖,通常有以下两种方式:
避免风险,通过采取一系列行动让团队确定风险所指的事件是不会发生的。例如,待迁移的数据可能和新系统不兼容,对于这个风险,我们可以在迁移之前验证他们之间的兼容性,从而说服团队相信它们是兼容的。
接受风险,通过分析让团队确定风险所指的事件是会发生的,并以此采取下一步行动。例如,新功能部署后可能会有Bug,对于这个风险,从历史经验看,新功能有Bug的可能性很高,那么团队可以确定它是会发生的,然后基于这个假设,我们可以采用A/B测试,金丝雀发布,蓝绿部署等措施降低新功能出现Bug时所造成的损失。
项目中常见的规避风险的机制有ADR(Architecture Decision Record), RFC(Request for Comments)等。
注意,和传统的风险规避策略不同,这里我并没有涉及到部分避免风险,因为我认为它是建立在接受风险的基础之上,然后通过一系列措施来降低损失,其本质和接受风险是一样的。
产生预期外损失:假设/依赖转换为问题
对于某些假设或依赖,我们从始至终都确定它们是会发生或不会发生的,直到产生了预期外的损失,这时假设或依赖被证明是错误的,它们就转换为了问题。这是一个被动转换,我们无法直接控制它。项目中常见的表现形式有线上Bug,法务纠纷,合规问题等。
这里我之所以强调预期外的损失,是因为有些假设或依赖会预期我们有一定的损失,这些损失是我们可以接受的,不会被认为是问题。例如,在进行数据库迁移时,我们会假设系统在切换数据库时有一段时间无法提供服务,无法提供服务会给我们造成损失,但它在我们预期之内,是可接受的损失,不是问题。但是,如果数据库切换之后出现了数据丢失的情况,违背了我们数据不会丢失的假设,造成预期外损失,那就是问题了。
有的预期外损失是因为假设或依赖错误引起的。例如,前端团队在拿到后端团队提供的API协议后就假设线上API和协议是一致的,而且在上线前都没有收集到任何反驳信息,于是一直按照该协议开发前端页面,直到上线后才发现API和协议不一致,出现线上问题。
有的预期外损失是因为假设或依赖缺失引起的。例如,前端团队在和后端团队沟通完联调时间后,一致认为联调时间是确定的,就没有将其记录到团队的假设或依赖列表中,也就没有收集反驳信息,从而一直按照联调时间制定开发计划,直到收到后端团队联调推迟的通知,这就导致前端团队因为没有充足的时间来修改联调问题而不得不推迟产品上线时间。
后置反馈循环
我们无法保证关注所有的假设和依赖,也无法保证所有被关注的假设和依赖是正确的,所以总是会有问题产生。我已经在《如何处理未知问题?》中讨论过这种情况,我们能做的就是通过降低损失和建立后置反馈循环来应对这些未知问题。
复盘是建立后置反馈循环的初始环节,团队中常见的机制是迭代复盘会议和PIR,它们可以增加团队的经验,也就是改善团队的流程和增强团队的能力,从而加强或减弱状态转换。
降低损失的本质是我们要尽量缩短后置反馈循环的周期,这样有助于团队不断积累经验并持续改进。若仅在项目末期进行一次产品发布,即便通过复盘能够总结经验,这些经验也难以反哺当前项目——因为届时项目可能已进入收尾阶段,面临团队解散、资源撤离,或因重大损失导致项目提前终止等不可逆状况。
我们也不能完全依赖后置反馈循环来减少问题,因为后置反馈循环存在损失且周期较长。我们应优先依赖由收集反驳信息和规避风险组成的前置反馈循环来减少问题,该循环不会造成损失且能够增加假设和依赖的准确性。
疑问的解答
现在让我试着解答一下我在文章开头的疑问
- 假设和风险的区别是什么?
答:假设和风险的区别是确定度不一样,假设是我们确定会发生或不会发生的事件,风险是我们不确定是否会发生的事件。 - 假设和依赖的区别是什么?
答:假设和依赖的区别是,我们无法通过改变依赖本身来增加确定度,只能被动接受或间接影响其代表的事件,通过改变自己来增加确定度。 - 假设必须在它成为假设之前得到证明么?如果我们不能证明一个陈述是真的或假的,就不能把它作为假设么?在一件事情没有发生之前,我们怎么证明它肯定会或不会发生呢?
答:假设需要证明,只要有人提出不同意见,我们就需要向其证明并说服其相信假设是真的,如无法说服对方,我们就需将其列为风险。这里的证明不是证明客观上事件会100%发生,而是证明我们主观确定事件会发生的合理性。 - 风险必须在它成为风险之前得到证明么?如果我们不能证明一个陈述有风险,就不能把它作为风险么?风险的标准是什么?
答:风险不需要证明,只要有人不同意它是假设或依赖,我们就需要将其设置为风险,然后通过规避风险来提高其确定度,从而说服不同意见者将其作为假设或依赖。 - 如果目前没有足够的信息证明一个陈述是对的或错的,我们该如何处理?
答:将其列为风险,后续通过规避风险来提高其确定度。 - 提出风险就必须同时提出解决方案么?对于目前没有解决方案的风险,我们该如何处理?
答:不需要,收集反驳信息和规避风险是两个不同的过程,它们可以在不同的时间段发生,我们可以先提出风险,然后再采取行动规避风险。
总结
首先,本文系统重构了RAID分析的理论框架,通过构建"认知状态-主观确定度"二维模型,解决了项目实践中常见的定义争议问题。其次,本文提出了动态象限转换机制,结合敏捷项目管理场景,阐释了假设、依赖、风险和问题的转化路径。最后,本文建立了"前置-后置"双反馈循环理论,为项目风险管理提供了可操作的方案。
鉴于我能力有限,思考的广度和深度可能存在不足,有错误的地方还请读者谅解,希望本文能给需要的人一些启发。