DDD编程

DDD现在是指导代码编写,甚至是架构设计的思想,要详细了解DDD必须先了解“聚合根、实体、值对象”的含义,这块网上已经有不少相关文章,为了避免踩坑,博主推荐一篇:聚合根、实体、值对象

一、界限上下文

最近看了欧创新老师使用DDD拆分微服务的思想,感受颇丰,特此总结一番。
欧老师将划定领域模型和微服务的边界分为了三步:
领域边界

  1. 在事件风暴中梳理业务过程中的用户操作,事件以及外部依赖关系等,根据这些要素梳理出领域实体等领域对象。
    • 以我现在在做的服务为例,我们要做医生助手相关的使用功能,其中包含医助服务模板,服务模板项目、子项目,用户购买的服务,服务的项目,子项目,待办事项,医生排班,收费项目字典,缴费记录,缴费记录详情等模块。
  2. 根据领域实体之间的业务关联性,将业务紧密相关的实体进行组合形成聚合,同时确定聚合中的聚合根、值对象和实体。在这个图里,聚合之间的边界是第一层边界,它们在同一个微服务实例中运行,这个边界是逻辑边界,所以用虚线表示。
    • 例如服务模板中包含项目实体,项目实体中包含子项目实体,
    • 同时模板中有值对象:服务名称,基准日期等,
    • 服务模板作为聚合根,是会和其他的聚合根例如地区、机构、店铺等聚合根通过id进行关联,以及一些名称字段冗余。
  3. 根据业务及语义边界等因素,将一个或者多个聚合划定在一个界限上下文内,形成领域模型。在这个图里,界限上下文之间的边界是第二层边界,这一层边界可能就是未来微服务的边界,不同界限上下文内的领域逻辑被隔离在不同的微服务实例中运行,物理上相互隔离,所以是物理边界,边界之间用实线来表示。
    • 上述中,服务模板,用户服务,医生排班,收费字典都可以作为一个单独的聚合,而他们都是为医助服务的,所以他们在同一个界限上下文中,他们与其他的界限上线文中的聚合,例如:用户,订单,商品,医院通过id进行关联,并可以进行部分字段冗余。

二、领域、子域、核心域、通用域、支撑域

我们以整体来看
4. 领域:整个公司的服务可以看做一个领域
5. 子域:领域下面可以分为用户中心、商品、订单等子域,用户子域又可以划分认证、权限等子子域
6. 核心域:核心域是与业务相关的,例如我们公司的核心域可以理解为:与医院交互的挂号服务、在线缴费、查询报告等数据服务、在线问诊这几个核心域
7. 通用域:指比较通用的一些领域,如用户、商品、订单等。
8. 支撑域:可以理解为一种功能子域,既不是公司的核心业务,又不是通用功能。

三、如何划分聚合

  1. 根据业务逻辑梳理出相应实体
  2. 梳理出聚合根和聚合:比如上面医生助手服务,可以划分为服务模板、用户服务、医生排班、数据字典等聚合,聚合的原则如下:
    • 聚合内是一套独立的业务模块,边界之外的东西与聚合无关,以此实现高内聚
    • 设计小聚合:聚合包含过多的实体,会导致实体的管理过于复杂,小聚合更能适应业务变化
    • 聚合之前通过聚合根进行关联,如果两个聚合中有些引用无法通过聚合根关联,就说明聚合的实体划分不合理
    • 在应用层实现跨聚合的服务调用:方便未来以聚合为单位拆分微服务
  3. 画出聚合内和聚合见的引用模型,确保聚合间只能通过聚合根的id进行引用,聚合内不限制,如下图所示,用户服务只关联了服务模板的id,用户服务项目不再通过id与模板项目进行关联
    用户服务聚合

四、领域事件

领域事件是指用户操作触发的一系列事件,比如:

用户下单购买服务,此时你需要将服务模板中的服务名称、服务内容数据同步到用户服务中,你购买服务是订单中心发送RocketMQ消息做的通知,你可能还需要下行调用行销中线查看下购买者相关的信息,放到用户服务中,此时的链路流程图如下所示:
用户服务领域事件
上图中,订单成功后订单中心发送RocketMQ消息通知用户服务,用户服务和服务模板是在同一个微服务中,但是是不同的聚合,可以通过rpc调用查询,对于行销中心的数据,是在不同服务中,也是调用rpc查询。
尽量避免同一个微服务中会有同时更新的分布式事务,如果有,绝大多数情况下,这两个聚合合为一个聚合更为合理,查询的话可以调用rpc,没有影响

发布了188 篇原创文章 · 获赞 117 · 访问量 38万+

猜你喜欢

转载自blog.csdn.net/lz710117239/article/details/103483069
ddd