09案例:货运平台应用的微服务划分
文章目录
今天我们主要来介绍货运平台应用的微服务划分的案例。
在前面的 04 课时中,我和你分享了 DDD 领域场景分析的战略模式,介绍了如何根据问题域,划分业务系统的领域和限界上下文。理想情况下,在划分完业务系统的领域和限界上下文后,我们就能够从高层的视野审视整个业务系统,并将限界上下文和微服务一一对应;接着再关注限界上下文内的领域模型,通过模型内的领域对象解决子领域内的特定问题,多个限界上下文通力合作共同解决整个领域内的问题,提供业务系统的解决方案。
在本课时,我们会首先介绍后续课程开展依赖的业务系统,也就是货运平台的功能需求,然后再基于这些需求划分货运平台的领域和限界上下文 ,最后对每个限界上下文进行战术设计,设计它们的领域对象和领域服务,为后续微服务的开发做好铺垫。
货运平台需求描述
项目实践最好是基于相对真实的业务开展,这样才能使你在项目实践中学到的技巧更好应用到实际开发中。
本课程的后续项目实践中,我们将会以一个货运平台应用作为微服务实战项目,它需要满足以下条件:
具备一定的复杂性,能够演示每个微服务的作用;
业务逻辑不会过于复杂,避免你在相关专业范畴的理解上浪费过多的时间;
具备一定的真实性,这能够帮助你将实战中学到各种知识直接应用到正式的开发环境中。
接下来我们就来概述货运平台应用的需求。
比如,现在有一家货运公司,它在每个城市都设立了对应的码头,客户可以在码头上寄送货物,还可以预定寄送的货物、寄送的目的地等。在这个寄送过程中,货运公司会根据寄送货物的相关信息分配对应的行程在各个码头中流转,最终送达目的地码头。客户可以在货物寄送的任意节点查看跟踪货物,并最后在目的地码头上领取货物。
这时货运公司就需要开发一个货运平台应用,帮助它管理码头的信息和货物的流转行程,并提供一定的方式让客户查询货物的流转情况。从上述的描述可以分析出货运平台的主要功能有:
码头管理 ,货运公司通过应用添加位于不同城市的码头;
路线管理 ,不同码头之间的流转路线需要在系统中指定,货物需要在指定的路线上在不同的码头上流转;
货物管理 ,包括货物寄送、货运流转记录、货物提取等;
费用计算 ,根据路线和货物的信息计算寄送成本。
下面我们就根据上述需求来划分领域和限界上下文。
领域划分
DDD 是以领域为核心的,实践 DDD 时要首先根据问题域划分出相关的领域,描述应用需要解决什么样的问题。领域中存在限界上下文,它用于解决领域内的特定问题,具备特定的职责,并存在边界。限界上下文内的领域模型具备较高的内聚性,不同边界之间需要透过显示边界进行通信。
在根据需求划分限界上下文时,我们可以从需求术语中提取一些概念对象,为它们绑定一定行为。接着将紧耦合的对象划分在一起,寻找它们的内在关系,尝试形成对应的限界上下文。最后,整理各个限界上下文的行为,验证它是否完整、清晰和高内聚。
从上面的需求描述我们可以简单地将用户分为货运人员和客户:货运人员需要借助应用记录货物在各个码头中流转的过程,配置码头之间的流转路线,管理码头;而客户并不关心这些细节,他们仅关心他们的货物到了哪里。根据这样的需求特点,我们先将货运平台应用划分为客户端货物查询领域和管理端货运平台领域(如下图)。
货运平台领域示意图
在确定了客户端和管理端的领域后,我们需要进一步对每个领域进行子域和限界上下文划分,这里主要介绍管理端货运平台领域的子域和上下文划分。
从前面的需求中,我们可以抽取一些关键性概念作为子域,帮助我们形成限界上下文。
货运公司希望借助货运平台帮助他们解决货物流转的问题,跟踪货物在不同码头之间的流转情况,这是应用需要解决的核心问题,也是核心领域所在,我们可以认为货运就是核心领域。货运上下文作为整个应用的核心,对货物的流转过程进行管理,包括寄送货物、流转货物、登记货物和提取货物等功能,有货物、货运单和货运记录等概念。
货物是在不同城市的码头之间进行流转,货运公司会在码头内对流转的货物进行登记。在扩展或者调整业务时,公司还会对码头进行增删改查等基本操作。码头作为一个子域,支撑货运核心领域,码头上下文主要解决码头的管理问题。
不同码头之间流转需要指定对应的路线,不能盲目运输;在寄送货物时也需要根据寄送的起点和目的地计算是否运输可达和相应的运输路线。这部分领域问题划分为货运许可子域,由货运许可上下文提供解决的领域模型。
计费上下文用于计算货物运输的费用,涉及货运、码头和货运许可等多个子域。
最后我们就细分出了管理端领域和限界上下文(如下图所示),货运、码头、货运许可和计费这 4 个限界上下文将通过它们边界内的领域模型提供特定的解决方案。
管理端领域和限界上下文示意图
在创建微服务时,我们希望每一个微服务都是单一职责的,并具备高内聚、低耦合的特征,限界上下文完美匹合这个特征。因此,我们可以将限界上下文与微服务进行一一对应。那么我们的货运平台应用的管理端就可以据此划分为 4 个微服务,分别是:
货运微服务(transport)
码头微服务(wharf)
货运许可微服务(permit)
计费微服务(charging)
战术设计
战术设计是对限界上下文的具体化和细致化,涉及具体领域对象的设计,这直接关系到技术层面的实现,往往是开发人员的主要关注点。前面我们划分出了货运平台管理端的限界上下文,接下来我们就来解析一下限界上下文内部的组织关系。
领域模型是对领域内的关键概念及其关系的可视化表示,它通过描述多个领域对象之间的关系,实现业务功能场景在软件系统的映射,为领域问题提供解决方案。战术设计的关键在于抽象出限界上下文中的领域对象及其关系,并通过领域模型图表示出来。
领域对象能够表达出业务意图,它们具备数据和行为,包括实体、值对象和聚合等概念:
实体是一种对象,有唯一的标识识别自身,具备一定的生命周期,并在生命周期内根据状态提供不同的行为,一般需要考虑实体的持久化问题。
值对象没有唯一的标识,在领域模型中是不可变和可共享的。
聚合由一系列实体和值对象内聚而成,用以表达一个完整的领域概念。每个聚合都存在一个聚合根(根实体)。
在货运上下文中,我们通过货运这个聚合来控制货运行为,货运就是这个聚合的根实体,货运上下文的建模如下图所示:
货运上下文数据项模型图
在上图中,引用类的实体和值对象来自其他上下文。货运实体有货运单 ID 这个唯一标识,它由货物实体、货运记录值对象、货运路线实体的引用、起始码头实体的引用、目的地码头实体的引用、寄货人实体和费用等组成,其中货运记录值对象记录了货物在多个码头中的流转过程,货物实体记录了需要运送货物的相关信息。
货运上下文关注的实体为码头,主要对外提供码头的管理功能。码头上下文的建模如下图所示,码头实体包括码头的承载量、可容纳的货物类型、码头地址等属性。
码头上下文数据项模型图
货运许可上下文的聚合根为货运路线,主要解决货运路线的管理和选择问题,建模如下所示:
货运许可上下文数据项模型图
货运路线聚合由货运路线 ID、起始码头实体引用、目的地码头实体引用、中转路线值对象、运转状态值对象和路线日志实体组成。其中,中转路线值对象描述了货运路线整个流转过程,包括从哪个码头出发、中间经过哪个码头、最终到达哪个码头、通过什么交通工具,以及预计要花多长时间等信息。运转状态描述了当前货运路线的运行情况。路线日志记录了每次货运路线运转情况,以方便后续根据数据调整货运路线。
计费上下文更多是费用计算的业务逻辑和算法,我们可以通过一个领域服务暴露它提供的行为。
多个限界上下文需要进行集成,才能完整解决领域内的问题。考虑到限界上下文的各种概念存在边界隔离的问题,在集成时需要注意不同限界上下文中领域概念的映射和翻译,避免对我们已经设计好的领域模型造成污染。限界上下文主要有以下几种映射方式。
合作关系(Partnership):两个上下文紧密合作的关系,一荣俱荣,一损俱损。
共享内核(Shared Kernel):两个上下文依赖部分共享的模型。
防腐层(Anticorruption Layer):一个上下文通过一些适配和转换与另一个上下文交互。
客户方-供应方开发(Customer-Supplier Development):上下文之间有组织的上下游依赖。
开放主机服务(Open Host Service):定义一种协议来让其他上下文对本上下文进行访问。
遵奉者(Conformist):下游上下文只能盲目依赖上游上下文。
发布语言(Published Language):通常与 OHS 一起使用,用于定义开放主机的协议。
大泥球(Big Ball of Mud):混杂在一起的上下文关系,边界不清晰。
另谋他路(Separate Way):两个完全没有任何联系的上下文。
而在我们的实践中,主要通过防腐层映射不同的限界上下文中相同的领域对象,保证整体领域概念的完整和统一。
一般来讲,我们会把领域对象的行为和数据都放在一起,以达到设计上高内聚和低耦合的目的,并屏蔽领域对象的细节,暴露公开的行为方法。当存在一些不归属于任何领域对象的领域行为或操作时,我们就将它们放在领域服务中。
领域服务是领域模型的一部分,应该尽量避免将过多的领域行为放在领域服务中,因为这会造成领域对象变成“贫血对象”,而一个合格的领域对象应该是行为和数据都兼并的。在我们微服务实践项目中,考虑到服务暴露粒度的问题,我们会把上下文暴露的领域行为都放到领域服务中,包括各个上下文的聚合根对外暴露的领域行为。
货运平台应用管理端的各个限界上下文包含的领域服务和职责有如下:
TransportService,创建新的货运、货运记录,查询货运状态等;
WharfService,增加码头、删除码头、修改码头信息和查看码头等;
PermitService,增加新的货运路线、修改货运路线、删除货运路线、为货运查找货运路线和记录货运运转状态等;
ChargingService,计算货运费用。
后续我们展开微服务业务开发时将按照上述构建的领域模型进行设计,在实践中验证领域模型的可行性,并调整不合理的地方。
小结
在本课程中,我们基于预设的货运平台应用需求,运用 DDD 进行该平台管理端的微服务划分设计:
使用 DDD 战略设计进行领域划分,划分出货运、码头、货运许可、计费等限界上下文,并初步映射出货运微服务、码头微服务、货运许可微服务和计费微服务;
使用战术设计,对每个限界上下文进行细分,梳理内部的领域对象交互逻辑,建立领域模型,并初步设计每个领域模型对象暴露的领域行为。
期望在一个课时中讲清楚领域驱动设计是不太现实的想法,但我希望通过本课时,可以加深你对领域驱动设计的理解和应用。在接下来的微服务实践中,我们将根据上述划分的微服务具体展开微服务组件的实践。
最后,关于领域驱动设计实践,你有什么经验和想法?欢迎你在留言区和我交流分享。
-– ### 精选评论 ##### **鹏: > 赞,赞,赞
文章作者 anonymous
上次更新 2024-06-10