从零教你领域模型在实际项目中的落地

最近学习了领域模型,虽然对领域模型中的每个概念都有大致的一个了解,但是总是在脑海里面模棱两可,看了极客 欧老师的DDD模型讲解理论太多,导致自己总是摸不着门路,不知道从何下手,怎么打破平时我们习惯性的E-R图建模思维,故在美团DDD实践的基础上在尝试一下自己模拟一下业务场景从头到尾的搭建一个DDD领域模型的业务场景。美团DDD实战项目链接:https://tech.meituan.com/2017/12/22/ddd-in-practice.html

文章就不从领域模型的概念开始说起了,在下面实际的项目里面会加入自己对于各个领域模块的理解,如果有什么不对的地方希望可以得到大家的纠正。

开场白:

至少30年以前,一些软件设计人员就已经意识到领域建模和设计的重要性,并形成一种思潮,Eric Evans将其定义为领域驱动设计(Domain-Driven Design,简称DDD)。在互联网开发“小步快跑,迭代试错”的大环境下,DDD似乎是一种比较“古老而缓慢”的思想。然而,由于互联网公司也逐渐深入实体经济,业务日益复杂,我们在开发中也越来越多地遇到传统行业软件开发中所面临的问题。在《复杂软件设计之道》里面作者说到了技术负债一词,我在一家千万级别的电商公司上班,听到这个词的时候立马就产生了共鸣,公司前期处于发展阶段,开发人员为了能将产品快速上市,导致各种业务杂乱无章,平时改一个很简单的功能点,改了一个地方,另外一个业务也用到了(老员工也不熟悉业务,代码毫无关联的地方),导致上线总是出现一些这没生效,那没反应的问题。等等

场景需求:

    抽奖平台

    1.抽奖活动有活动限制,例如用户的抽奖次数限制,抽奖的开始和结束的时间,抽奖人来源的抽奖机会类型(例如分享xx才能抽奖),等;

    2.一个抽奖活动包含多个奖品,可以针对一个或多个用户群体,奖品可以指定人群(标签,会员级别)发放;

    3.奖品有自身的奖品配置,例如库存量,被抽中的概率等,最多被一个用户抽中的次数等等;

    4.用户群体有多种区别方式,如按照用户所在城市区分,按照新老客区分,会员等级,活跃度等;

    5.活动具有风控配置,能够限制用户参与抽奖的频率。

大家先是思考下如果按照我们平时的开发习惯肯定就是先把数据结构建好(E-R),然之后开始用curd进行过程式代码的编写。

1、建立活动表(t_activity),活动规则表(a_activity_condition),活动奖品表(t_activity_prize)等

2、生成对应的mapp,dao等

3、建立一个lotteryService,里面存放了大量的mapper,各种if逻辑.


基于数据结构的开发模式

这种业务模型简单的时候还好,等业务复杂起来的话,会出现大量的业务逻辑存放在service里面,业务边界不明确,可能其中的某个方法某个判断也存放在其他的service里面,导致改某个片段的代码,其他的service也影响到了,或者说改ServiceA中的某段代码,ServiceB也影响到了。

    平时我们开发维护的时候产品说加一个xx需求,我们每次都需要想这样子改动会不会影响到其他地方,最后的出的结果就是,不确定会不会影响,或者直接和产品说:做不了等。导致产品为了兼顾开发的难度导致调整了需求,本来应该是让技术去适应市场的,现在却倒转过来,导致做出来的东西不符合原本的想法。


DDD领域模型的核心思想就是“高内聚,低耦合”,或者面向对象的设计说的“”,我们平时开发总是将业务逻辑和底层的模块(如mapper,redis的工具代码,es的工具代码)耦合起来,例如上面中的奖品,先出现redis,没有数据就查询mysql,我们一般写成


这方法一般是放在上面的  lotteryService里面,各位想下这本身是一个抽奖应用层,获取奖品本身的逻辑为什么会出现在这里,或者说抽奖逻辑为什么需要知道从redis取还是mysql拿呢?如果改成es?或者是其他的nosql,这样是不是要去修改lotteryService这个类,但是这个本身就不属于抽奖逻辑的,为什么最后需要去修改这个类呢?这就是面向对象说的,封闭原则。职责单一性。

接下来开始使用DDD领域模型去拆解这个抽奖业务

 战略设计

           战略设计是根据用户旅程分析,找出领域对象和聚合根,对实体和值对象进行聚类组成聚合,划分限界上下文,建立领域模型的过程。战略设计采用的方法是事件风暴,包括:产品愿景、场景分析、领域建模和微服务拆分等几个主要过程。战略设计阶段建议参与人员:领域专家、业务需求方、产品经理、架构师、项目经理、开发经理和测试经理。

            是不是很难懂?别急下面我们一步一步来。我们可以把抽奖拆解成C端和M端,M端就是我们常说的管理后台,设计抽奖活动的相关配置。接下来讲解的是C端


根据需求描述我们不难想到核心子域是抽奖子域。我们想下抽奖的逻辑,可以分为1)抽奖前判断用户是否满足抽奖条件;2)获取奖品池中的奖品,根据概率抽奖,得出中奖的奖品  3)得到的奖品进行判断用户是否瞒住得到奖品的资格;4)根据类型发放奖品。

可以得出,这个业务可以分成抽奖前,抽奖后两个领域。


2、战术设计

针对抽奖的子域部分,我们可以得出如下的集合根和实体


UserInfoFacade:防腐层的含义可以理解为适配器,由于UserInfo这个信息是在另外的微服务里面,我们需要通过http去获取相对于的信息,所有需要使用一个适配器去请求,理解为微服务里面我们服务间的接口调用。

同理我们对于发放奖品领域服务可以得出如下的建模


上面就是领域模型的建模过程了,现在把刚刚的业务整理到对应的模块里面,接下来直接上伪代码了。

DDD工程实现

在对上下文进行细化后,我们开始在工程中真正落地DDD。

模块

模块(Module)是DDD中明确提到的一种控制限界上下文的手段,在我们的工程中,一般尽量用一个模块来表示一个领域的限界上下文。

如代码中所示,一般的工程中包的组织方式为{com.公司名.组织架构.业务.上下文.*},这样的组织结构能够明确的将一个上下文限定在包的内部。

代码演示1  抽奖模块


代码演示1:LotteryCondition(活动限制聚合根)


      从中可以看到抽奖限制聚合根的主要功能就是整合几个实体或健对象对用户的活动权限进行控制。这一步是纯业务性的,没有涉及到db,缓存,等的操作,因为基础资源性的东西不应该耦合在业务里面。

代码模块2:UserInfoFacde (用户信息防腐层)


这一步可以理解为就是使用适配的方式调用第三方服务(微服务)。因为第三方的服务的参数总是和我们需要使用到的时候是不一样的,我们需要使用适配器的思维调用。

代码模块3:ActivityCondition


重点是checkActivityCondition()方法,做逻辑处理

代码模块4 :LotteryChance



发放奖品聚合根就不上代码了,关于资源库如何引入,我们我们可以看下Prize代码



将资源库的部分从原来的service中抽取出来,和业务分离开来,这是很有必要的,业务本身就不用管你的数据怎么样来,只是负责业务的逻辑。包括现在很流行的六边形架构,整洁架构等都是这个思想。把业务和底层分离,这个底层可以是框架本身,数据库等。

我之前公司由于需要把mysql读取的换成redis或者是本地缓存。如果把mapper代码放到service里面的话,这改动起来是非常巨大的一个工作,还会导致逻辑代码的改动。如果使用DDD的话是不是更加的符合面向对象的开闭原则呢?

最后上一下整个抽奖服务的代码



把具体的逻辑封装到独立的领域里面,这样看起来不是比各种状态散落在service里面舒服的多?服务里面只有领域对象,或者是聚合等。即使要改动数据的存储也不用改动到业务逻辑。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容