分布式电商营销系统的实践之路:抽象规则
前言
去年供职于一家电商公司,被分配到做商城营销体系的开发设计。本文章记录了我这个小菜鸟在营销设计中遇到的坑坑洼洼,以及在重构中的思路。
线性思维,线性设计
首先我们列一列营销组件有哪些。
- 满减
- 折扣
- 秒杀
- 组合购
- 换购
- 优惠券
- 新人有礼
- 邀请有礼
- 签到
- 红包裂变
- ...
其次是要知道营销在正向流程,即用户的下单路径中营销系统是如何起作用的,当然这只是简单的示意图,实际业务中要复杂许多。
在这种情况下我选择了一种“理所应当的设计”,即一种组件对应一个微服务。当然LZ不是说这种设计很糟糕,在营销需求不多的情况下这种方式能最快出成果。
其实在营销组件很多的情况下组件、服务一对一的设计仍有优点,因为符合开闭原则,需求变更再频繁,也只需对单个组件进行更改,不影响其他组件的正常工作。
实际上在下游与营销组件之间我会加一层聚合服务,用来收缩营销的边界,统一提供如计价、优惠显示等能力,避免给系统加入过多的耦合关系。
这种线性的服务设计能在迭代初期解决大部分问题,但暴露出来的问题也是显而易见的:
- 部署成本较高
- 代码库大量duplicate code,且组件之间的表设计有60%-70%相近
- 一些重要的主流程逻辑其复杂度会随着组件数量提升而提升,且严重依赖于单应用的响应时间,无法降级
重构:凡事都得按‘规则’来
在接受线性设计所带来的弊端后,我着手开始重构工作。这是个困难的工程,淘宝花了十年,经历6次重构,才实现了不上线就可以加组件,不得不说还是NB。
重构的方向::抽取共性,合并工程,组件不决定服务。
从业务中来,还得回到业务中去,和PM零零散散地归纳了现有营销业务的一些特点,以及将来的需求趋向。可以将现有营销十几种组件归为三类。
像积分权益、团购、优惠券等后置的营销活动,属于边界清晰、较为独立的服务,暂时不纳入重构的范围。这次讨论的是改价类和组合类这两种前置营销,即在结算前发生的营销活动。
-
改价类:针对单品进行改价,在购物车中直接显示活动价格。
-
组合类:针对多个商品进行改价,前置条件是1-n个商品通过数量/价格/sku类型 等触发的优惠,优惠形式也有多种: 直减/赠品/N元换购。
虽然分为两类,但这些组件最终的效果都是改变订单中的物品价格,改价类比较直观,而赠品和N元换购同样可以视为将某个商品自动加入到订单中,并对其改价的行为。
除了这点,组件们也有很多相同的属性,如生效时间段、限购、面对的用户群体、生效的sku范围等等。
新设计
面向对象的设计:所有依赖关系都终止于抽象类与抽象接口。
OOP的精神无处不可借鉴。在了解到这些共性之后,我们就可以抽象出自己的通用规则模型了,说到模型~~其实像营销体系这类复杂度较高的系统,实践DDD是个不错的选择~
在新的设计中,引入规则的概念。如果营销是类,那么规则就是这个类的一个实例。一条规则会拥有若干字段,按组分类之:
前置条件
- 用户资格
- 目标范围
- 门槛量
- 限购额度
- 生效时间
- ...
优惠参数
- 优惠方式
- 优惠内容
- ...
规格
- 优先级
- 类型
- ...
前置条件决定了如何触发这条规则;
优惠参数决定了触发后如何针对订单改价;
规格决定了这条规则的其他属性:
优先级用来控制规则之间的计算顺序;类型决定了这条规则的业务类型,也就是它代表的是什么组件,用于分组、互斥和触发组件的特有行为。
建表字段自然也就按以上来参考,基本是一一对应,当然最好是预留一些字段。不要高估自己的抽象能力,何况你永远不知道下一个需求有多“惊喜”。必要时也可以建立规则详情表,容纳更多的可能性,总是好的~
建立好规则表,其他相关的业务表也手到擒来了,如商品关联表,优惠记录表等等,这一块的共性很多,设计起来比较自由,就不赘述了,做好和规则记录的关联即可。
在此基础上,就可以开始重构业务模块了,对于一些CURD接口无非就是把库都集中挪到同一个地方了,比较简单。难点在于计价模块,如何通过规则类型来区别化表达这张规则表,从而各种营销玩法都能准确完成价格计算,这里我采用了注解驱动的策略模式。实现等到下次在讲~
排版不是很好,慢慢进步,peace~