读美团的营销业务实践以及领域驱动设计有后感 迈不过友情╰ 2022-09-10 02:18 160阅读 0赞 ![在这里插入图片描述][watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAQW5kcm9pZF9sYQ_size_15_color_FFFFFF_t_70_g_se_x_16_pic_center] ### 文章目录 ### * 1 背景 * 2 前言 * 3 实体类、值对象、聚合根 * 4 领域、领域对象、限界上下文 * 5 资源库 * 6 防腐层 * 7 领域服务 * 8 数据流转 * 9 DDD系统架构图 * 10 营销业务的实践 * 11 总结 # 1 背景 # > 近日完成了公司项目的营销活动的重构,重构内容是折扣码优惠计算的业务。新增满额减价、满件减价优惠规则,兼容以前的满额打折、满件打折。随后将要实现产品人员提出折扣码使用数量的统计需求。由于营销活动的业务逻辑需要经常变动,比如达到了优惠门槛的这个门槛可能要变动、优惠的规则要变动(比如又新增固定价格打折、固定价格减价)、甚至整个优惠主线都要变动(比如控制多种优惠互斥与否,由此会导致计算优惠时的价格参数要变动)。因此笔者想阅读一些关于营销模块的设计实践提高系统的可扩展性,做到技术服务于业务。于是乎深夜阅读了美团技术团队的[《设计模式在美团外卖营销业务中的实践》][Link 1]以及[《领域驱动设计在互联网业务开发中的实践》][Link 2]。 # 2 前言 # > 笔者听过DDD领域驱动设计,但仅限于听过的层面,并未仔细阅读过相关的文章,无独有偶阅读完了美团技术团队介绍的[《领域驱动设计在互联网业务开发中的实践》][Link 2]。笔者看完领域驱动设计这个文章后,并不觉得领域驱动设计有什么大的用处,或者说想不明白使用领域驱动设计有什么好处。阅读后的第三天向一位高级开发工程师咨询领域驱动设计相关的知识。(这位工程师重构的营销系统架构与领域驱动设计很像,估计对这方面比较熟悉,所以咨询他) > 注:本文章作为随笔记录下来,文章结构比较突兀随意,有些地方阐述结合了笔者的项目,不必纠结于某一点。文章仅供参考,有不正确的地方在评论中指出。 > 本文参考自美团技术团队的[《设计模式在美团外卖营销业务中的实践》][Link 1]以及[《领域驱动设计在互联网业务开发中的实践》][Link 2]。 # 3 实体类、值对象、聚合根 # * **实体类,Entity。** 一个实体类能直接映射到数据库的一张表。 * **值对象,Value Object。** 值对象的值通常不会改变,比如颜色信息`{"name":"天蓝色“,”rgb":"(0, 0, 240)", "css":"#005839"}`。以笔者重构的营销活动为例。营销活动中存储的优惠规则的值一般不会被改变,比如满额减价的`满10减2`的优惠规则`{"ruleType":"1", "fullPrice":"10", "fullAmount":"2", "fullDiscount":"", "fullRate":""}`,满额打折的`满10打折20%`的优惠规则`{"ruleType":"2", "fullPrice":"", "fullAmount":"", "fullDiscount":"10", "fullRate":"0.2"}`。通常值对象保存在数据库是以json格式,而反序列化成对象就是一个值对象。 * **聚合根,Aggregate。** 由根实体、值对象、实体组成。笔者认为聚合根其实是一个业务模型Model,比如一个订单,涉及到商品项、运费、税费、收货地址、享受的优惠活动。那么`一个订单Model`就包含`order_id、List<Product>、Shipping、Tax、Address、Discount`这些对象。 # 4 领域、领域对象、限界上下文 # > 现实世界中,领域包含了问题域和解系统。一般认为软件是对现实世界的部分模拟。在DDD中,解系统可以映射为一个个限界上下文,限界上下文就是软件对于问题域的一个特定的、有限的解决方案。——摘自美团技术团队的[《领域驱动设计在互联网业务开发中的实践》][Link 2] 笔者认为这些领域就好比商品、订单、支付、店铺、营销,每一个都是一个很大的领域。 > 与以往的仅有getter、setter的业务对象不同,领域对象具有了行为,对象更加丰满。同时,比起将这些逻辑写在服务内(例如Service),领域功能的内聚性更强,职责更加明确。——摘自美团技术团队的[《领域驱动设计在互联网业务开发中的实践》][Link 2] 领域对象不仅包含`set()`和`get()`,还有丰富的行为。 > 一个由显示边界限定的特定职责。**领域模型便存在于这个边界之内**。在边界内,每一个模型概念,包括它的属性和操作,都具有特殊的含义。——摘自美团技术团队的[《领域驱动设计在互联网业务开发中的实践》][Link 2] 限界上下文包含有领域对象,限界上下文具有解决领域问题的功能,说白了就是类中的方法能解决领域中的某个问题,而不是像实体类那样只有`set()`和`get()`。如下图所示: ![摘自美团技术团队的文章][watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAQW5kcm9pZF9sYQ_size_20_color_FFFFFF_t_70_g_se_x_16_pic_center] # 5 资源库 # **资源库,Repository。** > 领域对象需要资源存储,存储的手段可以是多样化的,常见的无非是数据库,分布式缓存,本地缓存等。资源库(Repository)的作用,就是对领域的存储和访问进行统一管理的对象。——摘自美团技术团队的[《领域驱动设计在互联网业务开发中的实践》][Link 2] 资源库能统一管理存储、访问对象,还能管理存储方式(关系数据库、非关系型数据库),技术选型(MyBatis、JPA等等)。 > 如下是Repository类中的一个方法: public class DiscountRepository { @Autowire private DiscountMapper discountMapper; @Autowire private DiscountItemMapper discountItemMapper; public Long insertList(DiscountEntity discountEntity, List<DiscountItemEntity> itemEntitys) { discountMapper.insert(discountEntity); discountItemMapper.insert(itemEntitys); } } > 缺点: * 使用方便性下降:Repository层其实是对mapper操作数据库的一层封装,当我在Service中需要操作数据库时,要调用Repository,在使用方便性上确实没有比直接在Service层中调用mapper方便。因为我不仅要定义Mapper接口并给出实现,并且还要定义Repository方法供调用方调用。这与以前直接定义Mapper定义接口并给出实现要麻烦很多。 > 优点: * 重构的复杂度降低:假如哪一天不想使用mybatis技术,想用另外的技术与数据库交互,那么我重构的时候只需关注Repository层并重构Repository层。Service层调用Repository层的地方无需关注。 * 单一职责、内聚度高:能看到Repository层的方法入参都是实体类Entity,Entity直接映射到数据库表。入参有哪些Entity就只需针对该Entity做增删改操作。而不需要做比如判空、空串之类的校验,更不用做不相干的Entity的增删改。不使用Repository层时,Service层的入参是一个业务模型Model(Model与Entity不同,Model并不能直接映射到数据库表。Model可能包含活动信息、购买的商品、享受优惠的商品、赠品、订单等。),当我在Service层调用Mapper时,就需要在service的各个地方写mapper代码,调用mapper前还需要做各种校验判断,代码可读性差,不优雅。 # 6 防腐层 # > 亦称适配层。在一个上下文中,有时需要对外部上下文进行访问,通常会引入防腐层的概念来对外部上下文的访问进行一次转义。——摘自美团技术团队的[《领域驱动设计在互联网业务开发中的实践》][Link 2] 其实就是对外提供接口,供外部系统来调用。笔者公司的项目也有采用这个,其实这也是设计模式中的外观模式Facade。 # 7 领域服务 # > 将领域行为封装到领域对象中,将资源管理行为封装到资源库中,将外部上下文的交互行为封装到防腐层中。此时,我们再回过头来看领域服务时,能够发现领域服务本身所承载的职责也就更加清晰了,即就是通过串联领域对象、资源库和防腐层等一系列领域内的对象的行为,对其他上下文提供交互的接口。——摘自美团技术团队的[《领域驱动设计在互联网业务开发中的实践》][Link 2] 本质就是我们常写的Service实现类。 # 8 数据流转 # > 如下图所示: ![摘自美团技术团队][aaf3281dc45f4652b0230c6a9e63495b.jpg_pic_center] # 9 DDD系统架构图 # ![摘自美团技术团队][watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAQW5kcm9pZF9sYQ_size_20_color_FFFFFF_t_70_g_se_x_16_pic_center 1] # 10 营销业务的实践 # 基本上都是采用设计模式去实现。笔者常用的套路是工厂模式+模板模式+策略模式。与美团介绍的差不多。美团介绍工厂模式可以加一个顶层的抽象工厂,笔者后期也加一个。关于设计模式这里不作详细阐述,详情可以参考笔者博客写的几篇设计模式的文章。 # 11 总结 # 领域驱动设计适合对中后期的系统做重构,或者系统一开始就以领域驱动去设计。基本上不可能在非领域设计的系统的初期阶段上做完全的实践。因为系统初期迭代的速度非常快、周期短,各种紧急需求赶马上线会导致在代码设计之初就没有考虑周全。随着业务的发展以及时间的沉淀,系统从快速迭代阶段进入成熟稳定阶段。业务量大且繁杂,由于经过时间的考验,系统中的某些业务基本稳定不变,可以考虑使用领域驱动设计去重构代码,提高系统的可扩展性、代码的可阅读性以及降低系统维护成本。 [watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAQW5kcm9pZF9sYQ_size_15_color_FFFFFF_t_70_g_se_x_16_pic_center]: /images/20220829/5b5dddba8bb14282a903f30d56b91f66.png [Link 1]: https://blog.csdn.net/MeituanTech/article/details/104991174 [Link 2]: https://tech.meituan.com/2017/12/22/ddd-in-practice.html [watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAQW5kcm9pZF9sYQ_size_20_color_FFFFFF_t_70_g_se_x_16_pic_center]: /images/20220829/00d3450db1a5481f93da9b5318ca4119.png [aaf3281dc45f4652b0230c6a9e63495b.jpg_pic_center]: /images/20220829/693e7941f0334b3385a0b17a55907138.png [watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAQW5kcm9pZF9sYQ_size_20_color_FFFFFF_t_70_g_se_x_16_pic_center 1]: /images/20220829/8158f9f1782044cca0566b0ac9490c9a.png
还没有评论,来说两句吧...