我们在设计一个领域业务模型的时候,往往喜欢闭门造车,通过一些领域建模的理论去实践一些设计的理念,在此我并没有贬低的意思,只是感慨电商技术发展这么多年,有些系统设计出来的模型还是那么脆弱不堪。本文中旨在结合自己多年的对电商交易的理解,分享一些自己的感受和设计的思路,大家一起学习进步。
什么是交易
交易是什么?可以理解为买卖双方签订合同的并履约的一个过程,签订合同是正向交易的职责,履约的发涉及到物流仓储发货等服务,这个可以理解实现合同的条款,合同的条款自己包含很多内容, 卖家卖什么产品给买家,提供什么产品,如果履约,如果违约了需要怎么赔付,如果产品的质量不符合要求,怎么维权。如图1,当然图1少了维权的部分,如果买家收到产品觉得不满意,或者产品的质量有问题,那么他可以根据条款,这边的条款可能包含一些隐性的条款比如电商法的一些要求,进行退款、换货等。
(图1)
在电子商务的交易中一般是人、产品的进行的一次互通的行为。从维基百科的定义来看交易其实包含物品或者服务,可能你既提供产品又提供服务,也可能你只卖服务,这个时候就没有产品。产品也可能不是真实存在的物品,它也可能是一种虚拟的商品,比如虚拟的货币。本文对有赞的设计和一般的设计按下不表,我先分析一般情况下交易设计的模型。
订单模型
一个实体模型就是一个独立的事物。每个实体都拥有一个唯一的标识符,可以将它的个体性和所有其他类型相同或者不同的实体区分开。许多时候,也许应该说绝大多数时候,实体是可变的。也就是说,它的状态会随着时间发生变化。不过,一个实体不一定必须是可变的,它也可能是不可变的。
在设计的时候关于实体和值对象的区分有时候是比较困难的,不同人可能对实体的理解不一样。比如对订单条目OrderItem是实体还是值对象?有的人认为是实体有的人认为是值对象。订单的话有订单id或者订单号来做唯一标识,这个共识会比较强,那么条目orderItemId是不是订单条目的唯一标识呢?在考虑这个是否是唯一标识的是不是有意义的下,我们可以跟值对象做对比,实体区别于值对象的最大原因是,值对象的值是不可变的,比如我们的收货人信息Receiver,在下单用户选择地址的那一刻就已经确定下来了,在订单域他就是一个地址信息,他的属性在订单的生命周期中不会改变,它只是用来发货的,它也没有唯一标识,所以他是一个值对象。一个订单可能有多个条目,每个条目是可以单独发货,在下单待支付的时候也可以对条目的商品进行改价,收货维权的时候买家或者商家可以选择某个商品进行退款,所以他在订单生命周期中会随着时间的变化而变化,所以它是一个实体,他的唯一标识就是orderItemId。
订单关系
订单这个聚合根我们再熟悉不过了,在很多电商领域都会提到这个聚合根,如图1大体的我们一般会得出这样的一个关联关系,这个关系有点单薄。虽然他可以体现出订单这个聚合的大体依赖关系,并且可以表达80%的场景,但是不能比较好的提现销售订单和采购订单的关系。销售订单主要是站在买家的角度阐明买家下单,采购订单主要是站在商家的角度向供应商下单。所以至少我们在订单中需要有一个值对象来标识这个关系,对应的条目其实也有这一层的关系。
订单条款
一般的电商交易都会有一些显示或者隐私的条款的,隐私的比如物流条款选择的物流配送方式,是自提还是快递或者无需物流,物流的显示条款可能有是否支持运费险。在维权方面还有一些隐性或者显性的条款,比如是否支持7天无理由退货。还要一些活动,比如定金预售,我们在商品下单的时候就会给用户提示下了定金是不支持退款的,我们这边的订单条款主要考虑的是显示的条款,隐私条例一般是电商法需要支持的,是一种默认的条款。
但是很遗憾,这些条款信息在我做过的交易里是没有很好的体现(因为历史的债务),甚至有些条款都是没有落库的,有些条款是通过扩展字段存储在订单扩展字段或者条目的扩展字段中。现在我们交易系统在很大程度上解决扩展性问题,都是通过扩展字段来承载,所以有了很多打标的接口,这样处理当然在性能上是有很大的好处,比如解决了性能问题,但是在复杂的业务系统中,其实就隐藏了一部分业务逻辑,在领域设计中是不被允许的,所以在解决性能问题的情况下我们可能需要平衡一些业务。大量的打标服务从而导致扩展字段的急速膨胀,最终解决的办法就是不断的扩充extra字段的长度。
订单调整
我们在下单支付等过程经常的会对订单进行一些调整,比如我们会对待支付的订单进行改价,这个一般的我们需要一个调整单,显示的记录这个调整。广义上来讲,我们订单的调整还包含一些费用,比如附加费、额外费用,商品或者运费的均摊,这些数据还比较复杂,一般的是作用在订单条目的,如果要在订单条目存储会比较复杂,因为包含的内容还比较多,比如调整价格,原价,调整原因,调整时间等等。所以这些调整信息比较适合单独拎出来存储。调整单的设计在ERP系统比较常见,比如我们在算出入库的时候,在月末结算不均衡的时候会手动入一个入库调整单。这里讲的订单调整不是ERP的调整单,它是针对交易的计算价格的时候,对商品价格的一些调整。
订单状态
订单状态记录着订单生命周期,其实还是比较核心并且复杂的一个实体。不同的订单类型的订单状态流转不一样,这个需要进行一个统一的设计,一般的话我们会考虑用状态机来实现。交易中的订单状态是可以枚举的,一般的我们会把订单状态设计成一个枚举类,但是订单状态其实承载了很多操作和控制状态流转的行为,所以它其实应该是有自己的唯一标识的实体。