本文来自微信公众号 ”B端产品周翔“,作者:周翔,纷传经授权发布。
在产品设计中,“状态”是非常重要的设计点,它看起来很简单,似乎只要定义好几个词就够了,但实际上有很多注意要点,稍不留神就会掉坑里的,所以很多同学在梳理的过程中会感觉越理越复杂、越理越混乱。这一篇我们就来详细聊聊产品状态的设计。
01
基础知识
1.1 状态的定义
状态是什么?
状态是对某一对象一个时间段内业务进展的概括性描述
我们将这个定义分解一下:
某一对象。状态是用来描述业务中一个具体对象的,每个对象的状态是独立的,只属于它自己;
一个时间段。状态表示的是一个时间段,而不是一个时间点,它不是一个瞬时动作;
业务进展。状态说明的是对象在业务中的进展;
概括性描述。状态具有概括性,是对对象的精简描述。
例如下图中淘宝的商品订单状态,描述对象是商品订单,每个状态都会持续一段时间,这些状态说明的是商品订单在流转过程中的进展,每个状态的描述都非常精简,格式也很统一。
图1 商品订单状态示例
1.2 状态的三要素
状态是由输入条件、状态描述、终止条件三个要素组成。
图2 状态三要素示例
1)输入条件
输入条件是进入这个状态的触发开关,当条件被满足,就会执行一次状态的迁移,即进入此状态。如上图中,“用户付款成功”后,商品就会进入【待发货】状态,“用户付款成功”就是【待发货】的输入条件。
2)状态内容
即这个状态是什么。
3)终止条件
终止条件是这个状态结束的开关,当条件满足时,此状态就会终止。如上图中的“商家发货”,就是【待发货】状态的终止条件。
上一状态的终止条件,是下一状态的输入条件,例如下图中“商家发货”是【待发货】的终止条件,是下一状态【待收货】的输入条件。
图3 终止条件与输入条件
无论是输入条件还是终止条件,都包含手动和自动两种:
手动:即需要用户手动触发,如“商家发货”,就需要商家手动点击“发货”按钮,或输入发货单号并手动提交成功,系统才可判断商品终止了【待发货】状态,进入【待收货】;
自动:即无需用户手动操作,系统根据已设置好的规则,当规则满足后,自动执行状态迁移。
这两种类型的条件可同时存在,也可只存在其中一种。如商品从【待收货】流转到【待评价】状态,既可手动触发,又有自动触发机制:
手动:用户主动点击“确认收货”按钮;
自动:从状态流转到【待收货】起开始计算,10天后,系统会自动确认收货,状态变更为【待评价】。
我们在设计状态流转时,会尽量减少需要用户手动触发的条件,改为自动触发,但很多时候系统无法做到完全自动,有些环节只能通过用户操作来完成。
然鹅,众所周知,用户都是懒的,用户都是上帝,我们无法强迫每个用户按照我们的要求去做,只要有需要手动触发的条件,就一定会有用户不主动做,这就会导致后续流程无法继续进行,所以对于状态流转比较重要的节点,我们大多会采用
手动为主,自动为辅
的原则,即预留一定的时间等待用户手动操作,当即将到达这个时间时,给予一定的预警提示,如若用户仍不操作,则在到达时间后由系统自动向更为常见的方向执行。
1.3 状态的作用
状态的作用主要有三个。
1)展示进展
向用户展示此对象的当前进展,以缓解用户的焦虑,降低内心的不确定感,从而提升用户体验。
2)便于描述
将对象不同阶段进行归纳,便于日常沟通。
3)统一规则
对于同一角色,一个对象在一个状态中的规则、操作权限是相同的,不应出现状态前半段权限是A,后半段是B的情况,这一点无论是对用户还是开发都是有意义的。
1.4 状态流程
将一个对象各个状态按时间线串联起来,得到的就是这个对象的状态流程。
图4 状态流程示例
02
设计原则
2.1 完整连贯
一个对象的状态是贯穿这个对象整个生命周期的,前后两个状态是紧密衔接的,中间不应出现任何真空时期。
图5 完整连贯示例
2.2 唯一性
唯一性是指一个对象在一个时间点只有一个状态,不会同时存在多种同级状态,这是很多同学在设计时没有意识到的一点,其中有两个场景是大家容易混淆的:
1)父子状态
一个对象有父子状态是比较常见的场景,例如前文提到的【待收货】,是一个比较笼统的父状态,它其实包含了【已揽件】、【运输中】、【派送中】、【待取件】多个子状态。
图6 待收货的子状态
定义父子状态的目的,是因为有时候子状态过多,在向用户展现时不方便,这时就可以将几个相近的子状态归纳为一个父状态,并以父状态展示给用户。在这类场景中,有的同学可能就会认为这个商品订单在一个时间点同时有两个状态,但实际上商品订单是以子状态来流转的,所以订单的真实状态是子状态,父状态只是套的一层壳。
2)多名称
多名称是另一个容易混淆的场景,因为有的同学会把多个名称误以为多个状态。
买家收到商品后,订单就应该从【待收货】向下一状态转移,这时我们有【已收货】、【待评价】两个名称可以用,内涵也是一样的。在这类场景中,虽然叫法不同,但其实还是同一个状态。
2.3 区分视角
虽然一个对象在一个时间点只有一个状态,但不代表只有一个名称。
在实际状态设计中,为了让不同角色的用户更好的理解一个状态的含义,有时即使是同一状态,针对不同角色用户也会使用不同名称。
2.4 统一规则
前面提到,定义状态很重要的一个作用是为了统一这个状态下对象的规则,但要想达到这一目的,就得在设计对象状态时遵守这一原则。
2.5 粒度适中
很多同学在梳理对象状态时,随着对流程的细化,会发现这些状态越理越细、越理越多,感觉这里可以加个状态,那里也可以加个状态,最后导致这一对象的状态特别多,状态流特别复杂,徒增用户理解和实现成本。
我们在定义对象状态时,在满足前面原则的前提下,应尽量减少引入更多的状态,控制状态粒度。
2.6 通俗易懂
状态名称需要精炼的表达出对象当前阶段的核心进展,并容易被大家所理解,如果实在找不到合适的通俗易懂的词,就要在状态旁边做好说明。
2.7 与业务流同向
在状态的定义中,我们强调了状态描述的是业务进展,这里包含的另一层意思是状态流程其实是对业务流程的概括,状态流是在业务流程的基础上总结出来的,所以状态流程与业务流程一定是同向的,即这个对象在业务上如何流转,它的状态就会以同样的方向流转。
03
设计流程
第一步、梳理操作流程
在设计原则2.7中,我介绍了状态流程与业务流程的关系,那我们是不是有了业务流程就能梳理出状态流程呢?
答案当然是否定的,不然我为什么要问呢。
业务流程之所以不能帮助我们梳理出状态流程,是因为业务流程只能帮我们提炼出状态三要素中的“状态描述”,无法帮助我们精准的确定另外两个要素——“输入条件”和“终止条件”。
大家都知道,在代码实现中,状态要想在系统中流转,需要精确的指令才能进行下一步,这些指令就是状态的“输入条件”和“终止条件”,而业务流程的粒度显然无法满足系统对“精确”的要求,例如商品流转的业务流程是:
图7 业务流程示例
在这个流程中,系统无法知道什么算“商家发货”、什么叫“物流配送”,所以业务流程无法直接指导系统进行状态流转,这时就需要我们梳理出对象在系统中的操作流程,通过系统中明确的操作或业务规则来向系统发出精准指令。
图8 操作流程示例(过程做了大量简化)
在这个操作流程中,对于系统自动处理的部分,可以通过增加一个名为“系统”的泳道,来体现系统自动完成的操作。虽然状态流程是在操作流程的基础上梳理的,但操作流程却是在业务流程的基础上细化出来的,所以业务流程也是很重要的。(要充分理解这一步,需要先理解业务流程和操作流程的含义和区别,不过这要扯很久,也偏题了,所以关于各种流程的介绍我们择日再聊)
第二步、归纳状态
在梳理的操作流程基础上,我们再依据前面提到的设计原则,提炼、总结出此对象的各个状态。
同样的,归纳状态时要明确状态的三个要素分别是什么。
第三步、梳理状态流程
有了第二步梳理的各个状态,顺着操作流程的方向,就能得到我们的状态流程了。为了沟通更方便,表达更清晰,状态流程图就是必不可少的,一般的状态流程图有三种表现形式。
1)纯状态流转
即流程图中仅体现状态的流转,不展示其他信息,如下图所示。
图9 纯状态流程图
这种形式很简单、干净,适用于向业务方、上级领导等不需要了解细节的关联方汇报,但对于开发同学来说肯定是不够的,这时就得采用后面两种形式了。
2)与操作流程结合
既然状态流程是在操作流程的基础上梳理的,这就说明这两个流程其实是可以合并处理的。
图10 状态流程与操作流程合并
如上图所示,在状态输入条件后展现状态名称,到下一状态开始前,中间过程均为属于此状态。
这种形式在操作流程较短时比较方便,可以用一张图体现两个流程,但当操作流程较长时,这张图的可读性就比较差了,不同信息间会产生干扰,这时就推荐用第三种方式了。
3)仅体现状态三要素
图11 仅展示状态三要素
如上图所示,这种形式是在上一形式的基础上,去掉中间无关操作,仅保留状态的三要素,这样既可以满足开发同学对触发条件明确的要求,也方便进行讲解汇报。
第四步、整理状态定义表
如果整个状态及流程容易理解,这一步可以省略,但如果定义的状态和相应规则比较复杂,那最好整理一张状态表来说明各个状态的要素、具体含义和相应规则,以便统一各方认识。
表1 状态定义表模板
04
关联对象的状态设计
大多数情况下,能够梳理清楚业务流程和操作流程,清晰准确的定义状态三要素,那状态设计基本就不会有什么问题了。
不过在状态设计中有一类场景会稍微复杂一些——关联对象的状态关系如何处理。
这里的关联对象,是指两个流程进展上相互有影响的对象,例如父子订单,父订单的流程进展受子订单的影响。
举个具体例子:
在某个需求管理工具中,假设需求的状态流程为:
待处理——开发中——测试中——已完成
这时小明创建了一个需求,同时在这个需求基础上拆分了两个子需求,那么父子需求的状态关系应该怎么处理呢?
这里有几个常见的处理原则。
4.1 一个对象仅有一个状态
父子对象虽然在业务上有父子关系,但各自状态是完全独立的,无论是业务角度还是实现角度都是这样,即便两者可能某些状态的命名都一样,但在逻辑上必须是互相独立,所以虽然状态名称相同,但实际是不同的对象,实质是不同的。
4.2 状态关系与对象流程关系相同
既然两个对象在流程上已经相互影响了,那么状态上也会存在一定的逻辑关系,因为状态流程是建立在对象业务(或操作)流程基础上,常见的几类关系有:
1)包含关系
即一个对象在多个状态间流转时,另一对象看到的仍是一个状态。例如商品消费订单和这个商品的配送订单,就是一对父子关系,消费者看到的消费订单是【配送中】,但配送订单可能会经过【分拣中】、【运输中】等等很多状态,这就是状态的包含关系。而之所以状态是包含关系,是因为这两个流程是包含关系,商品配送流程可以看作是商品完整流程中的子流程;
2)衔接关系
即一个对象先到某个状态,另一事项才会到某个状态。例如需求要想进入【已完成】状态,需要子任务进入【已完成】,父任务才允许【已完成】;
3)完全同步
即两个对象的状态是同步的,一个对象随另一对象状态变更而变更。
那有的同学会问了,在很多需求管理工具中,虽然父子需求存在父子关系,但为什么他们的状态是完全独立,相互之间不影响呢?
这其实也是体现了这一原则,因为在这些工具的定义中,父子需求的流程上相互没有影响,所以虽然他们存在逻辑关系,但相互间状态不影响。
到这里,关于产品状态的设计就介绍完了,如果各位读者朋友觉得写得还有点用,记得点个分享、关注一波哦~~