在之前的文章 业务需求分析中的三板斧-详细分析 介绍过,对需求的分析中,对于业务对象状态的分析尤为重要,也列出了一些分析对象状态的维度。但是,在很多情况下,即使你已经对需求分析得很详细了,对于需求中潜在的并发问题,却依然很难识别出来。究其原因,还是没有掌握识别需求中潜在的并发问题的方法。接下来我会介绍一种可以精确识别出并发问题的方法,让你在需求分析中再也不会因为并发问题而导致加班。
为介绍方便,以下会用一个电话呼叫的场景作为例子来介绍。呼叫需求的描述大致如下:
角色:有呼叫方、呼叫中心和被呼方三种角色,呼叫方是发起呼叫的用户,被呼方接收到呼叫请求的用户。 核心流程:呼叫方 通过呼叫中心 呼叫 被呼方 业务规则:
- 被呼方同一时间只能接收一个呼叫,或进行一个通话
- 被呼方可以拒绝接受呼叫,或者不接听呼叫
- 呼叫方发起呼叫之后可以随时取消呼叫
什么是并发问题
在介绍方法之前,首先定义一下什么是并发问题。较官方的定义是,并发问题是指在多任务处理的环境中,同时存在多个独立的任务,并且这些任务要共享系统的资源,例如内存、硬盘、网络等,这些任务之间相互影响,可能会造成一些不可预料的后果。这里有几个关键的要素,多个独立的任务,和多个任务都要共享系统的资源。在呼叫的需求场景中,多任务是指,同一时间可能会有多个呼叫方发起呼叫;多任务共享的系统资源,则是指这多个呼叫方都呼叫同一个用户,被呼方就是这多个任务共享的资源。这意味着在呼叫的场景下,必定会存在并发问题。
那问题来了,虽然我们知道了这个需求会有并发问题,但是要如何分析才能不遗漏地把并发问题都识别出来呢?有人会认为,对于这种场景的需求分析,只能靠拍脑袋,或者大家头脑风暴了。但是,拍脑袋或头脑风暴怎么能确保分析全了呢?这还真不是靠拍脑袋或头脑风暴就能分析全了的。
通过状态转移图分析并发问题
状态转移图
从之前的文章能得到这么一个推论,程序是一个状态机,而需求在机器上的描述就是具体的程序,所以对于需求本质上也是一个状态机。既然需求是一个状态机,而我们又可以用状态转移图来描述状态机,所以很自然地,我们当然也可以用状态转移图来描述一个需求。
上面的结论,是为了让大家能对需求分析这个事情多了一个思考的维度。当然,程序有很多细节,我们不可能人工地把一个程序的状态事无巨细地画出来。同理,需求也有很多细节,我们也不可能用状态转移图事无巨细地把需求描述出来。但是,我们可以通过状态转移图,把需求的核心部分画出来,这个我们可以做到,也应该在需求分析的时候做到。
可能会有一些疑问:
- 为什么要用状态转移图画出核心需求的状态?不画就不能分析需求的状态了吗?
分析清楚核心需求的状态是我们做需求分析的目的,当然可以不把状态画出来,但是用状态转移图描述一个需求的状态会让思路更清晰,阅读更流畅。 更重要的是,产品经理或其他开发人员看状态转移图容易看懂,而只有文字描述不易描述清楚。这是状态转移图最显著的优点。
- 一个需求的状态有很多,如何知道哪个才是核心需求的状态?
状态是依附在对象上的,要画出状态转移图,首先要找到需求中核心域的实体对象。关于如何确定核心域的实体对象,在这篇文章中 业务需求分析中的三板斧-详细分析 已经介绍过了。 但是对象可能也有很多状态,哪些状态才是核心?通常对象的核心状态是比较明显的,有个比较明显的特征,就是实体对象在业务中的生命周期,往往就是这个对象的核心状态。当然,如果这个对象有个不是生命周期但非常复杂的状态,当然也可以把它当做是核心状态来分析分析。
- 状态转移图画出来了怎么知道画得对不对?
状态转移图是需求状态的描述,状态对不对当然是要和产品经理好好确认清楚并达成一致。这也是为什么要画状态转移图的原因,只有把对象的状态确认清楚了,才能准确无误地实现产品经理的需求。如果没有状态转移图,只有文字描述,就很难和别人沟通清楚对象的状态了。
以呼叫为例子,我们可以根据需求,画出这样一个呼叫场景下的状态转移图:
所谓一图胜千言,这样把呼叫的状态转移图画出来之后,对于呼叫的分析就比较透彻了,也比较容易和其他人在设计上达成一致。
利用状态转移图分析并发问题
画出状态转移图之后还有另外一个很大的好处,就是可以用来分析并发问题。具体要怎么做?
-
首先要明确的是,状态转移图描述的是一类对象的状态,而不是多类对象的状态。描述多类对象的状态应该有多个状态转移图。在这个例子中,呼叫方 呼叫 被呼方,就会产生一个呼叫对象,那这个呼叫对象的状态就是我们要用状态转移图描述的状态。如果要描述呼叫方或被呼方的状态,描述的对象就变成了呼叫方或被呼方本身的状态,而不是呼叫的状态了。
-
其次,要区分清楚多任务和共享资源分别是什么。在这个例子中,可以认为存在三个独立的任务进程:呼叫方、被呼方、呼叫中心,而共享的资源则是产生的呼叫对象的状态。换句话说,也就是呼叫方、被呼方、呼叫中心都可以通过自己的行为修改呼叫的状态,如果同一时间被两个或以上的任务修改了呼叫的状态,那么呼叫状态就会出现混乱,从而产生了并发问题。
既然并发问题的产生是由于多任务对共享资源的竞争导致的,那我们如何从状态转移图中分析出来呢?状态转移图的每次状态转移都是由于某些事件引起的,而这些事件的发起者,就属于我们的识别出来的任务(角色)。因此,回归到并发问题产生的原因,我们可以得到一个规律,当对象处于状态A时,如果因不同的任务进程发出的事件,导致A状态的下一个状态出现不同的结果,那么状态A的状态转移就会有并发问题。
具体一点,就是我们需要识别出来导致这些状态转移的事件是由哪些角色引起的,分别用不同的颜色标记出来。当发现某个状态节点的出边有两种不同的颜色时,那么当对象处于这个状态下,想要转移到下一个状态,就要处理并发问题。
举个例子,在上述的呼叫转移图中,我们看到出边存在两种不同颜色的节点有CALLING和CONNECTING,我们可以用黄色来标记出来,如下所示:
我们可以分析一下:
当呼叫处于CALLING 状态时,呼叫方可以主动取消呼叫,导致呼叫从 CALLING 变成 CANCELLED;而被呼方也可以接收或拒绝响应,那呼叫的状态就有可能变成BUSY或者 CONNECTING;如果这两个操作几乎在同一时间发出,那就有可能出现被呼方明明已经接听了,但是这个呼叫却莫名其妙被取消了的情况。
同理,CONNECTING状态下也可能出现并发问题,分析的方法都是一样的。
这样分析真的不会遗漏吗
这种分析方法是依赖状态转移图的正确性的。所以想要做到不遗漏,关键还是要确保状态转移图的状态没有遗漏,以及状态分析是和产品经理的预期达成一致的。在这个前提下,再用这种方法分析并发问题,才能保证不遗漏。如果自己还没想清楚整个对象的状态,那就要先思考清楚对象的状态及其转移过程。
总结
虽然现在所负责的业务并发量不大,但是造成业务并发问题只需要两个用户就够了。对于并发问题,如果识别不全,带来的则是无尽的坑,以及其他同事的一起加班。所以精确识别并发问题对于提升效率十分重要。而结合状态转移图来分析并发问题,则是在实践中屡试不爽。