我正在参加「掘金·启航计划」
在对业务价值、业务用例和流程进行分析之后,接下来就要对业务进行详细分析。我们知道,程序本身就是一个状态机。那现在我们用程序来描述一个需求,也就是要用一个状态机来描述需求,那自然地,业务需求也是一个状态机。所以,分析需求,其实就是在分析如何用状态机表示这个需求。而在业务需求中,往往用业务对象来表示业务需求的状态。所以,在详细分析这一步中,我们要做的只有两步,识别业务实体对象,分析业务实体对象。
识别业务实体对象
如何从业务需求中识别出业务实体对象
- 动词名词法:一般来说,我们在讨论需求的时候,总能描述出一些需求场景,比如,用户A预约了一个会议;用户A进入了视频会议;等等,这个时候,我们就能显而易见地得到一些业务实体对象和这些对象的行为:视频会议是业务实体对象,用户可以加入视频会议,意味着视频会议这个对象需要提供加入的行为
- 用户流程分析法:通过主流程分析得到的业务流程,我们可以看到用户在使用我们的产品时,要经过哪些流程,这些流程中,应该会对应着一个或多个业务对象,那么在这些 业务流程中,使用动词名词法描述用户的使用场景,即可提炼出对应的业务实体对象。
如何判断找到的是一个业务实体对象
业务实体对象是和DDD中的实体对象是对应的,有几个明显的特征:
- 实体对象有唯一id进行标识,且id一般都可以区分为业务id和主键id,在需求分析中找到的是业务id。业务id的特点,就是具有业务含义的,用户能理解到这个id的含义的。比如,我们在设计数据库时,一个视频会议,会用一个数据库主键id来进行标识,这个数据库主键是无业务含义的,用户不能理解的,但是视频会议的会议号是具有业务含义的,用户知道这个会议号的背后有且只有一个视频会议。而我们在这一步的目的就是要找到会议号这个唯一标识视频会议的业务id,自然也就得到视频会议这个业务实体对象了
- 存在生命周期。一个业务实体对象,都会经历 创建,使用,销毁 这几个生命周期,并且可能会根据业务需求会再衍生出其他的生命周期。所以,判断找到的对象是不是业务实体对象,可以看它是否具备生命周期。
综上,我们可以简单地概括出以下内容:
分析业务实体对象
识别出业务对象后,我们接下来遇到的问题就是,要分析业务实体对象的什么内容? 总的来说,需要对业务对象分析以下内容:
分析对象的生命周期
对象的生命周期要从实际需求出发,从需求分析的过程中,我们分析出了业务流程,那么对应地,我们需要从业务流程中提炼出对象的生命周期。
比如,视频会议中会有录制的功能,那么我们可以提炼出Record这个实体对象。对应地,录制在视频会议中存在两种状态,录制未开始和录制已开始,其对应的行为就是开始录制和结束录制。所以录制这个实体对象,对应的生命周期可以如图所示:
分析对象的行为
- 对称的行为:行为应该是对称的,如果出现不对称的操作,应该说明具体的原因。
比如,静音必定会伴随着取消静音,这个行为是对称的;但是全体静音,并不一定会伴随着取消全体静音,因为在视频会议中同时让大家都开麦的场景几乎不可能存在,那么实现取消全体静音这个功能的优先级就没那么高,可以先不做。所以这个时候的行为可以是不对称的。
又比如, 以录制这个对象为例,存在开始录制的操作,必定会存在结束录制的操作。
- 重复的行为: 在同一状态下重复执行同样的行为,应该如何处理。
比如,A现在已经处于静音状态了,接着同一主持人,或不同主持人又对A执行了多次静音操作,那当出现这样的情况时,对主持人和A来说,应该怎么表现呢?
又比如,对于开始录制这一行为而言,在录制已开始的状态下,再次执行开始录制,该怎么处理呢?这时候就会发掘出开始录制这一行为需要满足幂等性了。
- 冲突的行为:是指对同一状态值执行不同的行为,导致产生不同结果时,该怎么处理。
比如,A、B是主持人,C是普通参会人,此时A申请开启C的麦克风,而B要进行全体静音,那么对于C来说,两个行为都有效,且这两个行为冲突了,那这个时候该怎么处理呢?
- 并发的行为:同一时间使用创建同一资源时,存在并发操作的场景,此时应该怎么处理。
比如,如果视频会议被设计成有人加入则创建,没人加入则不创建,那么当A和B同时使用同一个会议号加入会议时,就会存在并发操作,此时视频会议肯定不能创建多个,否则就会违背了一个会议号同一时间只能有一场视频会议的规则。对于这个场景,就需要使用分布式锁等措施来对并发操作进行处理。
又比如,视频会议中有A、B两个主持人,他们同时开始录制,那么此时我们的预期是同一时间一场视频会议只能存在一场录制。那开始录制的行为需要满足唯一性的约束。
分析对象之间的关系
对象的关系主要分析数量关系和依赖关系。其中,依赖关系尤为重要。
-
数量关系。数量关系比较容易识别,一般分为三种,一对一(1: 1)、一对多 (1:n)、多对多 (m: n)。识别对象之间的数量关系,有助于我们对数据库进行设计,通过对象可以映射到数据库表中,对象与对象之间要如何关联。
-
依赖关系。若两个对象之间存在依赖关系,意味着一个对象的创建需要依赖另一个对象存在,一个对象的销毁也可能影响到另一个对象,那么在分析时就要同时关注两个对象之间要怎么配合。
比如,我们分析出来视频会议和视频会议成员两种对象,那么视频会议成员必须在视频会议创建之后才会被创建出来,而在视频会议结束的时候,视频会议成员也必须跟着销毁。这涉及数据一致性的问题,理清这其中的依赖关系可以让我们知道对象之间应该如何保持数据一致性。
分析对象中的属性(状态值)
对象的属性,其实都是状态值。根据属性是否可变,分为两种,不可变属性和可变属性。
- 如果属性自对象诞生,直到对象消亡,都不会改变,这种叫不可变属性,比如对象id、创建时间、业务上的唯一标识(如身份证等)。这种不可变属性的要识别出来比较简单,而且因为其在对象生命周期不会变化,因此对业务流程的影响不大。
- 如果属性自对象诞生之后可以变化,则称为可变属性。对这种属性进行分析会比较麻烦,因为属性的变化往往带来一系列的变化,详情可以参照下面的状态值分析。
业务实体对象状态值分析
在业务需求开发中,对象的状态往往需要记录到数据库,或者其他的存储介质中。对于状态值的处理如果不当,会产生相当多的bug和技术债,更严重的甚至会导致用户数据丢失,引起丢单。因此,业务实体对象的状态值分析,是整个设计重中之重,值得多花一点时间来仔细梳理。
识别对象的状态
做过业务需求分析的同学都知道,要找齐对象状态并不容易,而且都会有如下几个问题:
- 什么是状态?
根据需求、交互和梳理出来的主流程,识别出哪些内容需要记录。所有用户设置的选项、客户端显示出来的值等等都是状态。注意,我们只需要将精力花在可变属性上即可,对于不可变属性,由于对业务的影响不大,在精力分配上可以不用过多关注。不过前提是你已经确认这个属性是不可变的。
- 还没进行系统设计,在实现时需要的状态值没找出来怎么办?
不需要找出系统设计时的状态值,那是系统设计要关心的事情,我们只需要找到需求中提到的状态即可
- 需求分析上提到的状态还是找不全怎么办?
不需要担心,显而易见的状态肯定能找到,其他没那么明显的状态,我们可以通过后续的几种技巧把它们找出来
- 如果发现有些状态没有依附在对象上怎么办?
这是不可能的,如果真的有这样的状态,那肯定是缺少了对业务实体对象的抽象,说明这里需要提炼出一个业务实体对象。
分析对象的状态
对于找到的状态值,逐个分析清楚:
- 初始状态值是什么
- 状态发生变化的判定条件:
- 谁能改变状态值(只有主持人才能静音别人)
- 在什么情况下不能改变状态值(主持人不能被静音、视频会议开始了不能修改等)
- 状态可以如何改变
- 改变状态有几种入口?(预约详情页能修改,视频会议界面中也能修改)
- 状态值如何发生转移?(假设一共有A、B、C三种状态,只能从A -> B -> C这样转移,现在是A状态,在经过什么操作之后会变成B状态,什么情况下不能从C状态变成B状态)
- 状态值可以是什么?
- 是否破坏了业务唯一性:状态发生变更后是否破坏了业务上的约束条件(比如 视频会议要求会议号唯一,如果支持人为修改会议号的话,修改后的会议号不能和已有的会议号重复,否则就会破坏了业务上要求会议号唯一的约束)
- 状态的边界值是什么:对状态的取值尝试拓宽它的极限,看它的极限值在什么地方。不止是产品经理,甚至是研发往往都会在这个地方缺乏考虑
- 数值型的最大最小值
- 字符串型的长度限制
- 字符串型的内容限制:如果是文本内容,输入一些违规词汇能否正确处理?如果是url、邮箱等有固定格式的内容,输入一些不符合格式的字符串是否符合需求?
- 时间型的时长极限值(比如视频会议的时长能否到达100年?)、时间最值(比如预约了一个100年后的视频会议?)、时间间隔的粒度等等(比如间隔1ms的时间开始一次录制?)
- 列表类型的极值,这可能是最容易被忽略的属性了,比如一次性传入一个长度是100w的列表? 这明显不合理,那么当你想要对这个列表长度做限制的时候,自然就会发现这部分需要产品定义边界值,或者分批处理
- 状态变更后的生效时机
- 更改了状态值,是对当前视频会议立即生效,还是对下场视频会议才生效?
- 状态生效后,会对哪些模块有影响
- 状态变更失败时,需要执行什么回退操作
- 比如,有人入会失败了,要通知xxx
需要注意的是,虽然上面列出了很多分析的维度,但并不是每个属性都会有这些维度。上面列出的只是一些可供参考的范围,只是提供了一些分析的方向,肯定不会是最全面的,在分析时还是要结合业务需求来分析。
这么分析有什么优劣?
优势
- 这套方法在我实际工作中运用了有两年多了,按这套方法执行下来,基本能做到需求的核心场景不遗漏,边界场景少遗漏,对后续的开发、测试环节都比较容易达成共识。
- 方便形成测试用例。作为研发也需要设计测试用例,不然你怎么知道你写的代码是不是已经满足了要求?
- 便于抽象出领域对象。领域对象是系统设计的基础,有了领域对象,你可以很方便地统一术语,也可以很方便地和所有需求相关方进行讨论。包括但不限于后端、前端、客户端、测试、产品经理等同事。
- 便于后续的留存。假设几个月甚至一年后再回看这个需求,只看产品经理的几页需求并不能很快地看出需求的业务规则。但是看你的需求分析可以在短时间内了解当时的需求。当然,对于其他想要接手这个需求的新人来说,也非常友好。
劣势
- 需要研发同学有一定的细心和耐心。
- 需要和产品经理,或者是真正使用的用户有充分的沟通。
- 需求分析的耗时会相比之前耗时长一点,但是对于后续的研发流程来说,把时间花在有方法指导的需求分析上,绝对比在后续流程中发现需求错漏导致返工要值得。