前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >案例教你一步步设计DDD微服务项目

案例教你一步步设计DDD微服务项目

作者头像
JavaEdge
发布2021-02-23 15:35:47
8740
发布2021-02-23 15:35:47
举报
文章被收录于专栏:JavaEdgeJavaEdge

1 功能描述

  • 请假人填写请假单提交审批,根据请假人身份、请假类型和请假天数进行校验,根据审批规则逐级递交上级审批,逐级核批通过则完成审批,否则审批不通过退回申请人。
  • 根据考勤规则,核销请假数据后,对考勤数据进行校验,输出考勤统计。

为了满足内外部人员,他们的在线请假、自动考勤统计和外部人员管理的需求,我们建设这个在线请假考勤系统,它是一个在线请假平台,可以自动考勤统计。它可以同时支持内外网请假,同时管理内外部人员请假和定期考勤分析,而不像HR系统,只管理内部人员,且只能内网使用。我们的产品内外网皆可使用,可实现内外部人员无差异管理。

2 场景示例

2.1 请假

用户:请假人

  • 请假人登录系统:从权限微服务获取请假人信息和权限数据,完成登录认证
  • 创建请假单:打开请假页面,选择请假类型和起始时间,录入请假信息。保存并创建请假单,提交请假审批。
  • 修改请假单:查询请假单,打开请假页面,修改请假单,提交请假审批
  • 提交审批:获取审批规则,根据审批规则,从人员组织关系中获取审批人,给请假单分配审批人

2.2 审批

用户:审批人

  • 审批人登录系统:从权限微服务获取审批人信息和权限数据,完成登录认证。
  • 获取请假单:获取审批人名下请假单,选择请假单。
  • 审批:填写审批意见。
  • 逐级审批:如果还需要上级审批,根据审批规则,从人员组织关系中获取审批人,给请假单分配审批人。重复以上4步。 最后审批人完成审批。
  • 完成审批后,产生请假审批已通过领域事件。后续有两个进一步的业务操作:发送请假审批已通过的通知,通知邮件系统告知请假人;将请假数据发送到考勤以便核销

人员组织关系场景分析结果图

3 领域建模

通过对业务和问题域进行分析,建立领域模型。向上通过限界上下文指导微服务边界设计,向下通过聚合指导实体对象设计。

3.1 领域建模过程

3.1.1 找出领域实体和值对象等领域对象

根据场景分析,分析并找出发起或产生这些命令或领域事件的实体和值对象,将与实体或值对象有关的命令和事件聚集到实体。

分析后的实体与命令的关系:请假单、审批意见、审批规则、人员、组织关系、刷卡明细、考勤明细以及考勤统计等实体和值对象

找出聚合根

根据实体、值对象与聚合根的依赖关系,建立聚合。

定义聚合前,先找出聚合根。

  • 从实体中可找出“请假单”、“人员”聚合根

再找出与聚合根紧密依赖的实体和值对象,会发现 请假单下的

  • 审批意见
  • 审批规则

人员下的

  • 组织关系

但之后发现刷卡明细、考勤明细和考勤统计等实体没有聚合根。 这类就需要分情况处理。

刷卡明细、考勤明细和考勤统计等实体间相互独立,找不出聚合根,不是富领域模型,但它们一起完成考勤业务逻辑,具有高业务内聚性。考虑将这几个业务关联紧密的实体,放在一个考勤聚合内。

最终建立请假、人员组织关系和考勤聚合:

  • 请假聚合有请假单、审批意见实体和审批规则等值对象
  • 人员组织关系聚合有人员和组织关系等实体
  • 考勤聚合有刷卡明细、考勤明细和考勤统计等实体

定义限界上下文

人员组织关系和请假,两个聚合共同完成请假业务,所以在请假限界上下文。

考勤聚合单独构成考勤统计限界上下文。

所以为业务划分请假和考勤统计两个限界上下文,建立请假和考勤两个领域模型。

微服务的拆分

一般来说,一个限界上下文即可设计为一个微服务。

划分微服务主要考虑职责单一原则。根据限界上下文即可拆为请假和考勤两个微服务:

  • 请假微服务包含人员组织关系和请假两个聚合
  • 考勤微服务包含考勤聚合

战略设计结束。通过战略设计建立了领域模型,划分了微服务边界。

下一步战术设计了,即微服务设计。

战术设计

根据领域模型进行微服务设计的过程。 梳理微服务内的领域对象,梳理领域对象之间的关系,确定它们在代码模型和分层架构中的位置,建立领域模型与微服务模型的映射关系,以及服务之间的依赖关系。

战术设计包括如下阶段:

分析微服务领域对象

领域模型有很多领域对象,但这些对象带有比较重的业务属性。

微服务内应该有哪些服务?服务的分层?应用服务由哪些服务组合和编排完成?领域服务包括哪些实体和实体方法?哪个实体是聚合根?实体有哪些属性和方法?哪些对象应该设计为值对象等。

服务的识别和设计

可将命令作为服务识别和设计的起点,步骤如下:

  • 根据命令设计应用服务,确定应用服务的功能,服务集合,组合和编排方式。服务集合中的服务包括领域服务或其它微服务的应用服务
  • 根据应用服务功能要求设计领域服务,定义领域服务。这里需要注意:应用服务可能是由多个聚合的领域服务组合而成的
  • 根据领域服务的功能,确定领域服务内的实体以及功能
  • 设计实体基本属性和方法

考虑领域事件的异步化处理。

以提交审批为例,流程:

  • 根据请假类型和时长,查询请假审批规则,获取下一步审批人的角色
  • 根据审批角色从人员组织关系中查询下一审批人
  • 为请假单分配审批人,并将审批规则保存至请假单
  • 分析得需要在应用层和领域层设计以下服务和方法
    • 应用层 提交审批应用服务。
    • 领域层 领域服务有查询审批规则、修改请假流程信息服务、根据审批规则查询审批人服务,分别位于请假和人员组织关系聚合。 请假单实体有修改请假流程信息方法,审批规则值对象有查询审批规则方法。 人员实体有根据审批规则查询审批人方法

聚合中的对象

请假聚合中,聚合根是请假单。

请假单经多级审批后,会产生多条审批意见,为方便查询,可将审批意见设计为实体。 请假审批通过后,会产生请假审批通过的领域事件,因此还会有请假事件实体。

请假聚合有如下实体:

  • 审批意见(审批人、审批状态和审批意见)
  • 请假事件实体

请假单聚合的值对象。请假人和下一审批人数据来源于人员组织关系聚合中的人员实体,可设计为值对象。 人员类型、请假类型和审批状态是枚举类型,可设为值对象。 确定请假审批规则后,审批规则也可作为请假单的值对象。请假单聚合将包含以下值对象:请假人、人员类型、请假类型、下一审批人、审批状态和审批规则。

  • 请假聚合对象关系图

人员组织关系聚合中,可建立人员之间的组织关系,通过组织关系类型找到上级审批领导。

  • 聚合根 人员
  • 实体 组织关系(包括组织关系类型和上级审批领导),其中组织关系类型(如项目经理、处长、总经理等)是值对象。上级审批领导来源于人员聚合根,可设计为值对象 人员组织关系聚合包含以下值对象
  • 组织关系类型
  • 上级审批领导
  • 人员组织关系聚合对象关系图

在确定各领域对象的属性后,我们就可以设计各领域对象在代码模型中的代码对象(包括代码对象的包名、类名和方法名),建立领域对象与代码对象的一一映射关系了。根据这种映射关系,相关人员可快速定位到业务逻辑所在的代码位置。在经过以上分析后,我们在微服务内就可以分析出如下图的对象清单。

应用层代码

应用层包括:应用服务、DTO以及事件发布相关代码。在LeaveApplicationService类内实现与聚合相关的应用服务,在LoginApplicationService封装外部微服务认证和权限的应用服务。

如果应用服务逻辑复杂的话,一个应用服务就可以构建一个类,这样可以避免一个类的代码过于庞大,不利于维护。

领域层代码

请假微服务领域层包含请假和人员两个聚合。人员和请假代码都放在各自的聚合所在目录结构的代码包中。如果随着业务发展,人员相关功能需要从请假微服务中拆分出来,我们只需将人员聚合代码包稍加改造,独立部署,即可快速发布为人员微服务。到这里,微服务内的领域对象,分层以及依赖关系就梳理清晰了。微服务的总体架构和代码模型也基本搭建完成了。

后续工作

详细设计

在完成领域模型和微服务设计后,我们还需要对微服务进行详细的设计。主要设计以下内容:实体属性、数据库表和字段、实体与数据库表映射、服务参数规约及功能实现等。

代码开发和测试

开发人员只需要按照详细的设计文档和功能要求,找到业务功能对应的代码位置,完成代码开发就可以了。代码开发完成后,开发人员要编写单元测试用例,基于挡板模拟依赖对象完成服务测试。

总结

DDD战略设计从事件风暴开始,然后我们要找出实体等领域对象,找出聚合根构建聚合,划分限界上下文,建立领域模型。

战术设计从事件风暴的命令开始,识别和设计服务,建立各层服务的依赖关系,设计微服务内的实体和值对象,找出微服务中所有的领域对象,并建立领域对象与代码对象的映射关系。

FAQ

CQRS其实就是读写分离,主要解决DDD的复杂查询问题。一般是写库和读库分离,但是实效性不容易保证。其实你也可以在同一个库,用领域或者应用查询服务来完成复杂查询的。

  • 推广活动为一个聚合,直播推广为一个聚合,但是这两个聚合之间又是有联系的,比如直播推广可以参与推广活动。那这样这个命令到底属于哪个聚合呢?还是说将推广活动作为一个值对象呢 聚合内有实体吧,看看这些实体跟那个聚合根关联紧密,生命周期归聚合根管理,就放在跟聚合根在一起的聚合内,如果别的聚合要用,有两种方案,第一种是通过聚合根引用实体。第二种方案,在另外的聚合内将这个实体设计为值对象或者实体,值对象或实体的数据来源于另外的那个聚合的实体。
  • 关于ddd读写那块,我最近看到有的文章说在ddd化为微服务中最好做到读写分离,将读的逻辑放在service(domain层的),写和其他的逻辑放在entity中,但这里会遇到spring di问题,entity不方便做di,我看的两种方法一种是通过entity的工厂类来实现实体的di,另一种是同一用repository工程类来注入。是否还有更好的方法,还有这种读写是否适合ddd(因为我自己适着用充血模型来写也发现很多时候复杂的读逻辑不适合放在entity中实现) 复杂的查询建议独立出来,通过CQRS来实现,可以根据时效性要求设计为读写同一个库或者读写库分离的方式,复杂的查询逻辑可以独立为应用或者领域服务。复杂聚合的实体初始化建议用工厂类服务,简单的直接用构造函数就可以了。
  • 请假单在请假聚合里,审批人在人员组织关系聚合里,在请假单聚合根(leave.java)会关联人员聚合的人,然后导航到审批人。
  • “DO 是实体和值对象的数据和业务行为载体,承载着基础的核心业务逻辑。通过 DO 和 PO 转换,我们可以完成数据持久化和初始化。”“第二步:提交审批facde实现DTO转DO”一直不理解不了DO对象,老师,你可以结合这章的内容,代码说明下DO对象吗?这个DO对象应该放在项目结构哪个目录下? 这个DO对象是领域模型的实体对象,放在Entity目录下。DTO转DO是将外部请求数据转换为领域模型的实体对象。
  • 审批规则值对象有查询审批规则方法?不应该通过领域服务或聚合根做查询吗?这里的值对象是充血模型? 审批规则有两个: 审批规则的配置数据,独立存在 保存在请假单上的审批规则,它根据请假基本信息匹配审批规则配置数据后获得,只要请假基础数据不变,你就不需要在每次提交审批的时候去查询审批规则的配置数据。依附于请假单的这个审批规则是值对象。
  • 组织关系是一个实体,记录人员关系和上级领导,上级领导数据来源于人员聚合根,所以设计为值对象。
  • 一般通过聚合根来调仓储服务。用仓储服务来实现数据的初始化和持久化。大批量的数据查询建议用CQRS模式。
  • “提交下一步审批”这一步是不是不应该这样,是不是根据“审批”业务流,产生的审批事件自动决定是到最后一步了,还是继续下一步审批,因为审批人只需要关心自己的审批就可以了,不要关心是否还有一下审批人(也就是不需要点击“发往下一个审批人”),也样流程更合理? 这个是系统内部判断的,根据审批规则和当前审批人的角色来确定是否还有下一审批,如果有则获取下一审批人和角色,给请假单分配下一审批人
  • 有时候为了完成领域层的业务设计,有的实体对内部属性的访问进行了控制,但是在仓储接口存储的时候又需要持久化下来,这时候该怎么做呢? 把DO实体传给仓储接口即可,仓储实现内部会将DO映射成PO对象,然后PO对象就可以实现持久化。
  • 如果我要对审批规则做增删改,怎么设计比较合理?在请假领域里新增一个LeaveApproveRuleService,里面加上增删改的方法,可以吗?(传统方式) 可以。不必纠结聚合根。聚合根目的是保证聚合内的数据一致性。审批规则内不会出现这种请假。可以用领域服务或实体的方法。
  • 一个人可能会有多级组织关系,比如项目经理,处室领导,部门领导。中间还会查询过滤,所以设计为实体。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-01-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 功能描述
  • 2 场景示例
    • 2.1 请假
      • 2.2 审批
        • 人员组织关系场景分析结果图
        • 3 领域建模
          • 3.1 领域建模过程
            • 3.1.1 找出领域实体和值对象等领域对象
            • 找出聚合根
            • 定义限界上下文
        • 微服务的拆分
        • 战术设计
          • 分析微服务领域对象
            • 服务的识别和设计
            • 聚合中的对象
              • 应用层代码
                • 领域层代码
                • 后续工作
                  • 详细设计
                    • 代码开发和测试
                    • 总结
                    • FAQ
                    相关产品与服务
                    云直播
                    云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档