基于DDD(领域驱动设计)的微服务设计实例
⽬录
项⽬基本信息:某在线学习系统,学⽣预约公开课,预约成功后通知。
⼀、战略设计:
战略设计是根据⽤户旅程或场景分析,提取领域对象和聚合根,对实体和值对象进⾏聚类组合成聚合,然后划分界限上下⽂,建⽴领域模型。
战略设计采⽤的⽅法是事件风暴,包括:产品愿景、场景分析、领域建模和微服务拆分⼏个主要过程。
1、产品愿景
产品愿景是对软件产品进⾏顶层价值设计,对⽬标⽤户、核⼼价值、差异化竞争点等信息达成⼀致,避免产品设计和建设偏离⽅向。
本项⽬产品愿景:为了满⾜⽤户在线预约公开课的需求,我们建设⼀个在线选课系统,该系统是⼀个在线选课平台,可以⾃动统计学⽣的选课情况,并在学⽣成功选课后发出确认消息。
通过产品愿景分析,项⽬团队统⼀了产品名称,明确了项⽬⽬标和关键功能。产品原型分析对于初创系统明确系统建设重点、统⼀团队建设⽬标和建⽴通⽤语⾔是⾮常有价值的。如果系统建设⽬标和需求⾮常清晰,这⼀步可以忽略。
2、场景分析
场景分析是从⽤户视⾓出发,探索业务领域中的典型场景,出领域中需要⽀撑的场景分类、⽤例操作以及不同⼦域之间的依赖关系,⽤以⽀撑领域建模。
⽤户旅程分析和场景分析是领域建模的主要分析⽅法,项⽬团队成员⼀起⽤事件风暴的⽅法完成在线选课的⽤户旅程分析。根据不同⽤户⾓⾊的旅程和场景分析,尽可能全⾯地梳理从前端操作到后端业务逻辑产⽣的所有操作、命令、领域事件以及外部依赖关系等信息。
场景⼀:学⽣选课。
1)学⽣登录系统:验证登录信息
2)选择课程:搜索/浏览感兴趣的课程,确认选择课程。
3)消息提醒:系统⾃动发出选课成功邮件,提醒学⽣上课时间。
场景⼆:取消选课。
1)学⽣登录系统:验证登录信息
2)取消选课:打开未完成的已选课列表,取消指定课程。
场景分析结果⼊下图所⽰:
3、领域建模
领域建模是通过对业务和问题域进⾏分析,出领域对象以及它们的业务⾏为和依赖关系,建⽴领域模型的过程。有了领域模型后,你就可以向上通过界限上下⽂指导微服务边界设计,向下通过聚合划定微服务内的逻辑边界,指导完成微服务内的实体和值对象设计了。
领域建模是⼀个收敛的过程,主要分为三步:
第⼀步:提取领域对象。从业务操作或⾏为中,抽象并提取领域实体和值对象等领域对象。
第⼆步,构建聚合。从众多实体中出聚合根,出与聚合根依赖的实体、值对象等,建⽴聚合。
第三步,划分界限上下⽂。根据业务及语意边界等因素,将多个聚合划分到⼀个业务上下⽂环境中,确定领域模型的界限上下⽂边界。1)提取领域对象
根据场景分析,分析并出发起或产⽣这些命令或领域事件的实体或值对象。将命令和事件与实体或值对象建⽴关联关系。通过业务⾏为和领域事件分析,我们提取了产⽣这些⾏为和事件的领域对象,如课程、学⽣选课、认证信息、系统通知等实体和值对象,如下图所⽰:
2)构建聚合
在定义聚合前,先出聚合根。在前⾯提取的实体中,可以发现“学⽣选课”、“系统通知”具有聚合根的特征,如:有独⽴的⽣命周期,有全局的唯⼀ID,可以创建和修改其他对象,可以有独⽴的模块来管理它们。所以,我们将“课程”、“学⽣选课”和“系统通知”定义为聚合根,然后出与聚合根紧密依赖的实体和值对象。我们发现课程、⽤户与学⽣选课紧密管理,⽤户与系统通知紧密关联,它们分别形成
选课聚合和系统通知聚合。
经过分析,我们建⽴了选课、系统通知两个聚合,如下图所⽰:
其中,选课聚合有课程和⽤户等对象,系统通知聚合有系统通知和⽤户等对象。
3)划分界限上下⽂
出所有的聚合后,我们可以根据业务职责和业务语义上下⽂边界将所有聚合划分到不同的界限上下⽂边界内。基于上边的分析,可以划分出选课和消息两个界限上下⽂,建⽴了选课和系统通知两个领域模型。
4、微服务拆分
理论上,⼀个界限上下⽂就可以设计为⼀个微服务,但还需要综合考虑多种外部因素,⽐如职责单⼀性、软件包⼤⼩、团队沟通效率、技术异构等⾮业务要素,以及弹性伸缩、版本发布频率和安全等⾮功能需求。
在这个项⽬⾥,划分微服务主要考虑了职责单⼀原则,也就是根据界限上下⽂进⾏划分,拆分为选课和消息两个微服务。
到这⾥,战略设计就结束了。通过战略设计,我们建⽴了领域模型,确定了领域模型内部的对象和它们之间的依赖关系,划分了界限上下⽂和微服务的边界。下⼀步就是战术设计了,也就是微服务设计。我们以选课服务为例,来讲解其设计过程。
⼆、战术设计
战术设计是根据领域模型完成微服务设计的过程。这个过程会梳理微服务内的领域对象,梳理领域对象之间的关系,确定它们在代码模型和分层架构中的位置,建⽴领域模型与微服务模型的映射关系,以及微服务之间的依赖关系。
战术设计主要包括两个阶段:分析微服务领域对象和微服务代码结构。
1、分析微服务领域对象
领域模型⾥有很多领域对象,但是这些对象带有⽐较重的业务属性。要完成从领域模型到微服务的落地,还需要进⼀步细化分析和设计。
在领域模型基础上,我们需要进⼀步细化这些领域对象以及它们之间的依赖关系,补充事件风暴过程中可能遗漏的业务和技术实现细节。所以,这个分析和设计过程会⽐事件风暴详细很多。
我们⼀般会分析以下关键内容:
微服务内应该有哪些服务?
服务如何分层?
应⽤服务由哪些服务组合和编排完成?
领域服务包括哪些实体和实体⽅法?
哪个实体是聚合根?
实体有哪些属性和⽅法?
哪些对象应该设计为值对象?
1)服务识别和设计
命令往往是由于外部操作后产⽣的⼀些业务⾏为,⼀般也是微服务对外提供的服务能⼒,往往与微服务的应⽤服务或者领域服务对应。
我们可以将命令作为服务识别和设计的起点,服务识别和设计的具体步骤如下:
a. 由于应⽤服务主要⾯向⽤例,我们可以先根据命令设计应⽤服务,确定应⽤服务的基本功能,应⽤服务应该包含哪些服务,服务的组合和编排⽅式是什么样的?这些服务主要来源于领域层的领域服务或其他微服务的应⽤服务。
b. 根据应⽤服务功能要求设计领域服务,定义领域服务。这⾥需要注意:应⽤服务可能是由微服务的多个聚合的领域服务组合⽽成的。
c. 根据领域服务的功能,确定领域内的实体以及实体⾃⾝的业务⾏为。领域服务主要完成聚合内垮实体的复杂业务逻辑,要注意避免滥⽤领域服务,⼀⾯实体变成贫⾎模型。
d. 设计实体的基本属性和⽅法。
我们以确认选课这个动作为例,来说明服务的识别和设计过程。
确认选课的主要流程如下:
a. 验证学⽣是否已经选择过该课程,如果已选择,则提⽰不能重复选课。
b. 保存学⽣选课数据。
c. 向学⽣发出选课已成功消息。
通过分析,我们需要在应⽤层和领域层设计以下服务和⽅法。
应⽤层:确认选课应⽤服务
领域层:查询学⽣选课(验证是否重复选课)服务、保存学⽣选课服务,位于选课聚合中。
学⽣选课实体包含查询学⽣选课⽅法和保存学⽣选课⽅法。
下图是分析出来的服务以及它们之间的依赖关系:
另外,在服务识别时,我们还要考虑是否有领域事件发⽣,领域事件是否会触发下⼀步的业务操作,业务操作是发⽣在微服务内的其他聚合还是其他微服务。对于微服务之间的领域事件,⼀般建议优先采⽤领域事件驱动的异步化数据最终⼀致性⽅式,尽量避免采⽤同步服务调⽤⽅式,这样可以解耦领
域模型和微服务。
⾄此,服务识别和设计过程就完成了,接下来进⼊聚合内领域对象的设计过程。
2)聚合内对象
在选课聚合中,学⽣选课是聚合根。课程和学⽣来⾃其他聚合,所以可设计为值对象,操作⼈是不可变对象,也可以设计为值对象。
因此,选课聚合的值对象包括课程、学⽣、操作⼈。
综上所述,我们就可以画出选课聚合领域对象的依赖关系了,如下图所⽰:微服务在哪里

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。