大厂的营销逆向域DDD实践
0 商家的痛点
订单退款后优惠券没被回收、退款过程中商家对营销资产没有直观感知、黑产党尝试薅商家资产羊毛等,给商家造成不好体验。为此构建营销逆向域,如资产冻结、解冻、回收等能力。
1 业务形态
商家设置一种满 10 元送优惠券的活动,而后消费者下笔 20 元订单得到一张优惠券,然后申请订单全额退款,商家希望能回收优惠券。
而另一位消费也花20元,只申请 5 元部分退款,商家表示订单达到门槛,不打算回收券。这是最基础的一个业务场景,营销逆向域就是处理该券的逆向操作,技术则关心触发逆向的条件和对应的营销资产种类。
1.1 营销资产种类
营销资产,指订单满足某些营销活动的门槛后由营销系统发放给消费者的虚拟资产或权益。常见有优惠券、优惠码、积分、储值金等;虚拟权益有砍价,助力,抽奖等(消费者在消费后可以获得一定的资格参与其他互动类的活动),营销资产利于促进消费者回购,帮商家稳定客源。
按虚拟资产的价值属性区分:
-
金本位资产
店铺储值、现金红包、京豆等,这类资产的特点是与资金直接挂钩,均可直接用来无门槛消费
-
普通资产
优惠券、积分等,本身不与资金直接相关,营销价值大于资产价值。对金本位资产的逆向操作更严肃,普通资产的风险控制更多由商家操作
1.2 按资产价值分类
1.2 触发条件
- 买家申请退款时,需冻结营销资产
- 买家撤销退款或各种关单场景,需解冻资产
- 商家同意退款,退款完成需要回收资产
- 买家修改退款单时需要看申请金额的变化,来决定冻结还是解冻资产
门槛需要与正向发放的门槛需要保持一致,即不足发放门槛时,需要处理资产。关于冻结解冻回收状态机如下图所示:
在整个交易链路,营销逆向系统在中台的位置处于逆向链路下游,在用户下单行为完成后且发生退款才涉及,流量不高但计算精准性高要求,中台位置:
由产品配置活动的逆向规则,实际退款按配置规执行。下单链路会提供活动的快照信息如优惠门槛、发放资产等。营销逆向域依赖规则引擎,负责底层组件调用,最终通过发放中心异步操作资产,一次退款的主要业务流程如下:
2 模型构建
为保持领域层(domain)整洁,只依赖内部common包,依赖层(dependency)和基础设施层(infrastructure)通过依赖倒置方式依赖领域层,屏蔽外围的接口实现。上游应用层(application)以拓展点接入交易系统,处理请求和外部查询。参考DDD得到包结构:
2.1 领域设计
领域模型需要保证高内聚低耦合,有对应的行为支撑模型的属性:
① 实体(Entity)
- 商品(goods):订单中的商品、活动参与商品和退款商品,具有商品各种计算能力,如判断商品的剩余金额,商品之间各种逻辑关系等
- 资产(equity):各类虚拟资产的统一抽象,一般来自正向的快照信息,提供资产操作的行为和各种统计视图
- 门槛(conditionTable):抽象活动的发放规则条件,由正向的 snapshot 解析而来。提供通用化的参数转化行为
② 值对象(ValueObject)
- 订单(order):上游交易告知的订单信息,包括订单商品,金额等信息
- 退款单(refundOrder):同样由交易产生,包括了申请退款的商品,申请的退款金额,件数以及可退金额等信息
③ 聚合根(Aggregate)
活动聚合(refundActivity):对门槛、商品和资产实体做一个整体的聚合,抽象成一个退款活动,对外统一操作。
④ 服务(Service)
在领取层统一提供 refundService 服务,提供能力:
- 计算抵扣金额
- 资产逆向操作
- 订单资产信息查询
⑤ 上下文(Context)
RefundContext:逆向域的上下文信息,包括订单退款单等,在定制规则引擎中提供上下文服务。
2.2 正逆向领域映射
开发难题
因为不同领域之间底层数据不互通,使得逆向域解析正向模型时变得十分困难,导致正向域产生的优惠快照(snapshot)在逆向域无法被识别。
对此,采用模型关系映射,解决不同领域间模型和参数的转化问题。以满 X 条件模型为例,正向模型有:
-
两个参数:
-
amountAt 满X元(件)
-
amount 实际X元(件)
-
-
两个 optionBind 绑定条件:
- amountPrice 满X元
- amountNum 满X件
高度抽象灵活的模型,不同参数绑定表示不同业务含义,但也带来问题,如:
- 满X元、满X件的业务校验逻辑不同,在流程中除了要关心模型本身是啥,更要关心模型绑定的参数,破坏内聚原则
- 用户仅退款场景,没有件数信息,存在特殊逻辑
所以逆向域构建过程中,采用含义清晰的积木。实际映射配置:
<identification name="ump.refund.setting.amount.num.resource">
<params>
<param key="amountNum">
<mapping domain="UMP" meta_id="ump.pbb.condition.amountOver" bind="amountNum"/>
</param>
</params>
</identification>
identification
标签定义受体模型params
定义模型下的参数列表key
定义模型下的参数名mapping
定义参数值的来源,从哪个领域(domain
)的哪个模型(meta_id
)中取哪个绑定(bind
)或者参数(value
)
定义模型映射关系,即可直接将 A 领域的模型转换成 B 领域的模型(包含参数),省去业务自己去解析积木,转换参数,再构建的过程。
3 复盘
存在正逆向的门槛条件不同业务需求,如虽下单满足指定金额送优惠券,但只要发生退款即回收券,此时逆向的门槛条件高于正向,又或者订单金额全退才回收优惠券等,未来逆向域考虑提供通用的退款模板,只需配置“AtOnce”或“All”这样的普通条件即可实现条件判断。
逆向域作用范围可再拓展,涉及退款退虚拟资产的业务都可接入,如充值储值卡送优惠券,用户退储值账户,也可接入营销逆向域。
逆向域诞生前,营销活动通过监听退款消息来做逻辑,杂糅在系统各组件。新系统打散活动的概念,抽象出各种规则,使退款不再依赖于具体业务,而依赖于各种配置规则。
4 总结
本文解析营销逆向域的业务形态及逆向域的领域实践,解决资产的逆向回收,支持多种退款场景,支持不同业务规则,实现逆向流程配置化。
相比下单域,逆向较稳定,易收拢业务、方便制定规则、能力可复用。但在领域设计上还可继续抽象与中台其他系统联动。
关注我,紧跟本系列专栏文章,咱们下篇再续!
作者简介:魔都国企技术专家兼架构,多家大厂后端一线研发经验,各大技术社区头部专家博主,编程严选网创始人。具有丰富的引领团队经验,深厚业务架构和解决方案的积累。
参考:
本文由博客一文多发平台 OpenWrite 发布!