• 南山 置顶
    2019-10-23
    老师,麻烦有空帮忙看一下
    场景:电销
    根据任务类型的属性创建具体的定期执行任务,调度器把到点的任务放到执行器里去执行。执行完了等待下一次执行,对任务生成的明细可以填写沟通记录(第三方服务)但是本服务要提供此字段查询
    过程中记录统计日志。每个任务类型在查询他的任务时查询和列表展示字段集合都不一样
    任务执行过程:从数据源获取数据 -> 根据任务配置的过滤规则过滤 -> 生成任务明细(有过期时间) -> 1.自动分配给销售/2.销售主动去领单,过程中生成任务执行日志,统计日志

    领域对象:任务类型、任务、任务明细、日志、过滤规则、字段、销售、
    聚合A:聚合根-任务,任务明细-实体,值对象:日志、任务类型、销售
    聚合B:聚合根-过滤规则,
    聚合C:聚合根-字段,值对象,展示字段属性定义集合、查询字段属性定义集合

    问题:
      1.一个聚合中,允不允许只有一个实体和一些属性值?
      2.是否合理?不合理该怎么设计呢?
      3.任务是根据任务类型创建出来的,聚合A是不是不合理?或者实体的初始化可不可以依赖它的值对象呢?
      4.任务类型决定它可以进行哪些过滤,实际创建任务时才会真正选择使用哪些过滤规则,过滤规则算什么呢?能作为一个独立的聚合吗?
      5.字段也是同样的,并且字段是没有一个生命周期的,这种情况下是不是作为值对象更合理? 但是聚合A和B都用到了字段,值对象能在多个聚合公用吗?
    展开

    作者回复: 我先理解一下你说的业务场景哈。不知道理解的对不对?不对的地方请你指出。由于不好展示事件风暴的过程,我就口述吧。
    你描述的业务场景主要包括这两个部分吧。
    流程一:创建任务
    1、根据任务规则获取任务基础数据,生成任务。(产生任务已创建事件,领域对象包括:任务生成的基础数据、数据过滤规则、任务、任务类型)
    2、自动将任务分配给销售。(销售的数据应该来源于其他系统,这个过程实际上是一个给任务赋值的过程,领域对象包括:销售)
    3、销售领取任务。(给任务分配销售)
    这个过程领域对象包括:基础数据、数据过滤规则、任务、任务类型、销售。
    命令有:创建任务,给任务分配销售。
    领域事件有:任务已创建。

    流程二、任务执行
    1、销售查询并获取任务,执行任务。(不清楚你说的字段在这个过程是什么含义,是查询时勾选类型吗)
    2、任务执行完成后,记录执行结果,产生任务执行日志。(产生任务执行日志已创建事件,领域对象有:任务、任务日志)
    3、统计日志。这一块不清楚你的业务逻辑和流程。
    因为有统计日志,是不是就会去查询任务的执行日志,如果是这样的话,任务日志就需要设计为实体,跟任务关联,这里任务是聚合根。
    这个阶段的领域对象有:任务和任务执行日志。
    命令有:查询任务,生成任务执行日志。
    领域事件有:执行任务日志已创建。

    结合这两个流程,我们整体来分析一下。
    领域对象包括:基础数据、数据过滤规则、任务、销售、任务类型、任务执行日志。
    由于销售人员数据来源于第三方,以值的形式存储在任务中,因此我们可以将它设计为任务的值对象。
    任务执行日志依附于任务,但是由于它后续要做查询和统计分析,因此将它设计为被任务引用的实体。
    任务类型是任务的值对象
    其它的基础数据、数据过滤规则这两个领域对象很独立,你可以理解他们是独立的实体,或者说一个实体就是一个聚合。
    但是这样设计在代码目录设计时会显得比较单薄,一个聚合会有一个仓储和聚合自己的代码目录结构。因此我们可以将这两个实体可以直接放在任务的聚合里,但是他们的生命周期不受任务这个聚合根管理。
    这样的话,我们就可以只建立一个任务聚合。这个聚合的聚合根是任务。它引用的实体包括任务执行日志,任务的值对象有:销售、任务类型。还有两个独立实体:基础数据和数据过滤规则。
    说明一下:
    在不少的数据统计和计算场景中,有很多实体之间相互独立,只参与计算和统计分析,但是这类场景中业务内聚性又很高,你找不出管理这些实体的聚合根。我称这种业务模型是非典型领域模型。虽然有些方面(比如聚合根)不符合DDD的一些原则,但是我们也可以按照DDD方法来完成设计。

     4
     31
  • 胖虎
    2019-10-31
    老师,能用电商的例子说一下聚合根的使用场景嘛

    作者回复: 电商里面比较典型的几个聚合根,比如:库存、商品、订单等等。
    以订单为例,订单在聚合里是聚合根,与订单关联的有订单明细和收货地址。订单明细包括商品ID,商品名称,价格以及数量等信息,由于订单明细是多个,它是一个集合,它被设计为实体,被订单引用。而订单只有一个收货地址,这个收货地址的值来源于你个人中心维护的收货地址,收货地址只能被整体替换,所以它被设计为值对象。

     2
     5
  • 渊虹
    2019-10-24
    老师,有个问题不明白,麻烦解惑。投保聚合和客户聚合中,投保人和被保人跨聚合引用到客户的id,需求是查询以客户s为被保人的保单。就需要跨过聚合根,直接访问被保人这个值对象。这个是不是和只能通过聚合根访问聚合内其他对象的理论不一致

    作者回复: 被保人这个值对象以属性嵌入的方式嵌入保单聚合根中,查询客户保单时你不需要到客户聚合去查询客户信息了,直接根据客户信息在投保聚合查保单就可以了,当然这个客户信息不只是ID。
    说明一下:这个跨聚合引用是在生成保单的时候,通过客户聚合根查询获取的客户信息,从客户聚合获取客户信息后,客户的信息就作为值对象的值嵌入到了保单实体中。

     4
     5
  • 美美
    2019-11-06
    老师,想请教一下
    我们的场景是:商家后台上,商家可以进行门店管理,收银pos机相关的设置,营业相关的设置
    背景:商家后台已经存在,且商家基础系统、门店基础信息、pos相关信息,数据模型已经存在,各调用方是直接访问数据库的
    目标:将商家、门店的基础信息,经营设置信息,抽象出来形成商家域 统一对外提供能力

    想通过DDD的思想来进行建模,感觉无从下手,麻烦老师提供点思路
    展开

    作者回复: 后面会有建模方法的介绍。
    你可以试着从用户旅程入手,根据流程看看会发生哪些领域事件,再找找是哪些命令触发这些领域事件的。梳理的差不多的时候,你就找找这些命令都是哪些实体的行为,这样就可以找出好多实体。根据实体可以找出聚合根,再根据聚合根找出关联的实体和值对象。这样聚合就找到了,然后对聚合划分限界上下文。这样就可以设计微服务了。

    
     4
  • stg609
    2019-10-29
    首先,几乎每个留言都会评论!必须给个大大的赞!

    其次,我有3个疑问,
    1. 聚合中可能会有实体,那允不允许直接把实体类型作为属性的类型或返回值暴露给外界?
    2. 如果允许,那外界就可以直接获取其中的实体,然后调用者可以直接使用实体中的一些相关方法?这样似乎就违反了聚合很的设计?
    3. 如果不允许,那外界如果需要得到某个实体的数据,要怎么操作?封装成 DTO 吗?

    比如: Aggregate a 中包含一个b属性,b是一个实体。b 中包含操作该实体的方法 M。那外界调用a.b 就会直接获取到 b 这个实体,然后可以直接调用 M 方法。
    展开

    作者回复: 非常感谢!
    首先你说的外界,要明确一下,这个外界是微服务内,不同的层之间?还是指微服务之间,也就是微服务外部调用。
    如果是在微服务内,不同层之间的话,由于运行在同一个微服务内,实体是可以被其它高层服务获取的,这时实体以DO对象的形式,存在于应用层和领域层,你可以使用DO对象的方法。但是不建议将实体的方法编排放在应用层,而是在领域层封装成领域服务后暴露给应用层。
    如果这个外界是微服务之间的话,你需要将实体DO数据转换为DTO对象后,才能被外界使用,这时,外界是不能调用实体的方法的,因此可以隐藏实体核心业务逻辑的实现方式。

    
     4
  • 蜗牛慢慢爬
    2019-10-23
    听了这么多节课,总结一下还是太抽象了

    作者回复: 基础篇主要讲解DDD的基础概念和设计理念,所以相对抽象一些。后面会有中台业务建模和微服务设计案例,比较好理解。敬请期待。

    
     4
  • 密码123456
    2019-10-23
    聚合。用界限上下文把细粒度的实体圈起来当做一个组织,选出组织的董事长。一个组织和另外一个组织交流的时候,只需要通过一个董事长,能够了解该组织的全部非隐私信息

    作者回复: 类比的不错。

    
     3
  • 三木子
    2019-10-23
    什么是充血模型

    作者回复: 说到充血模型,就离不开贫血模型。
    先说一下贫血模型吧,贫血模型是指使用的领域对象中只有setter和getter方法,所有的业务逻辑都不包含在领域对象中而是放在业务逻辑层。
    而充血模型将大多数业务逻辑放在领域实体中实现,实体本身包含了属性和它的业务行为,它在领域模型中就是一个具有业务行为和逻辑的基本业务单元。

     2
     3
  • 祥敏
    2019-11-01
    您好,第四讲和第五讲都在讲述微服务内部的拆分与设计,是关系紧密的两讲,反复听了有三四遍略有收获和疑问。

    从业务顺延的角度拆分,聚合、聚合根、实体、值对象这四个概念很好的模拟了业务的世界,就像面向对象所讲的一切皆对象,对象与对象之间的关系(聚合)。

    疑惑有两点:持久化和实体之间关系的灵活性。

    持久化(以关系型数据库为例):聚合内部强一致性,聚合之间最终一致性。聚合是由多个遵循一定规则的实体组成,实体的描述由值对象组成,这样的问题在于聚合、实体、值对象和数据库之间的对应关系不够直接,同时事务管理也比非DDD的方式复杂,如果严格遵循DDD的原则去做,可能会在对象->数据库这个关节会有较多的问题要解决。

    实体之间的关系:跨聚合之间实体不能直接发生关系,这个是否会不够灵活,实践中是否会引发一些问题?
    展开

    作者回复: 如果数据一致性没什么问题,那就选择自己最合适的方式去做吧。但是一定要记住,边界要清晰,聚合之间的服务和数据不要耦合,耦合度太高,以后领域模型和微服务演进就很难。

    
     2
  • zj
    2019-11-01
    一个聚合可能对应一堆实体及值对象,一个聚合对应一个仓储也即数据持久化单元。那如何实现聚合到持久化单元呢

    作者回复: 它是通过仓储实现的。
    由于领域模型中的DO实体与数据模型中的PO不一定一一对应,所以聚合里的实体在持久化时,会有一个DO到PO的转换过程。仓储持久化的组织者是聚合根。具体的实现你可以用MyBatis等组件,目前来讲现在的几个主流持久化组件,在仓储实现持久化方面使用起来还不是特别的顺手。
    在某些不强调数据一致性的聚合中,个人感觉你可以突破聚合根,按照你习惯的方式去完成数据持久化。

    
     1
  • 张迪
    2019-10-29
    跨多个实体的业务逻辑通过领域服务来实现。
    其次它作为聚合的管理者,在聚合内部负责协调实体和值对象按照固定的业务规则协同完成共同的业务逻辑。
    怎么感觉 聚合根做的事情和领域服务一样?

    作者回复: 两个出发点不一样,聚合根主要是从实体关联的角度,关注数据一致性。领域服务主要组合的是实体业务行为。

    
     1
  • 杨杰
    2019-10-23
    “一个微服务可以包含多个聚合,聚合之间的边界是微服务内天然的逻辑边界。有了这个逻辑边界,在微服务架构演进时就可以以聚合为单位进行拆分和组合了,微服务的架构演进也就不再是一件难事了“
              目前我们在微服务内部,对聚合的要求降低了。也就是说一个微服务内部的数据结构是随便互相访问的,实体也是贫血的模型。主要是考虑:服务层已经分为微服务层,聚合服务层(BFF层)了,微服务之间通过消息来解耦;如果微服务内部再分层,引入领域事件,感觉有点儿太复杂了。不知道这样合适不合适?

    作者回复: 因为微服务的架构演进,会有功能和代码的拆分和重构的过程。而一般来讲聚合的内聚性很高,聚合内的功能相对稳定,我们可以聚合功能和代码为单位在不同的微服务之间进行功能和代码的重构。
    如果聚合之间代码和业务边界不清晰,聚合之间数据和服务可以随便访问,就会因为耦合度过高,代码很难剥离,最后微服务架构演进时又要在走一遍从单体拆分微服务的过程。后面的章节我会专门讲微服务架构的演进。

    
     1
  • TH
    2019-10-23
    在别处看到,持久化只能由聚合根来进行,并且由于聚合是用来保持聚合内部的数据一致性,因此持久化时应当持久化整个聚合。

    另外还有一个疑问,在与外部聚合协同时只能通过外部聚合根的ID,这个具体是怎么实现的呢?如果当前聚合不持有外部聚合根实体,要怎么使用它的业务功能呢?通过外部聚合根暴露REST API吗?如果是一个单体应用怎么做到不直接调用外部聚合根呢?

    作者回复: 是的,在一个聚合内是由聚合根来管理和协调所有实体和值对象的生命周期的,所以在一个聚合内可以保证数据的一致性。
    由于多个聚合运行在同一个微服务内,在应用层我们是可以拿到其它聚合的聚合根的DO对象的,拿到聚合根后你就可以通过聚合根引用聚合的内部实体和值对象。

    
     1
  • 守候、
    2019-10-23
    老师,就基础篇。我的理解是基于事件风暴(头脑风暴)定义出实体与值对象,并能识别出根对象,进而得到聚合,并清晰领域边界、松耦合。从而达到服务化确定服务的边界!但是这其中事件风暴如何组织进行是否有策略或者说工具技术。如果团队成员就事件风暴无法达成共识,如何进一步推进?

    作者回复: 你好,事件风暴会有专门的一节介绍。

    
     1
  • herry
    2020-02-06
    老师你好,
    聚合有一个重要特证叫做不变性:聚合内有一套不变的业务规则,各实体和值对象按照统一的业务规则运行,实现对象数据的一致性

    这里对不变性有疑问,感觉比较抽象。

    用独立性来分析聚合的话:

    拿贴子和回复来说,贴子和回复是可以独立存在的,所以这两个不是聚合

    一个订单和它的商品行不能独立存在,这里一个订单是聚合,订单头是一个聚合根,关联了订单行

    这两种情况下的不变性该怎么分析呢?

    展开
    
    
  • maomaostyle
    2020-02-05
    请问老师聚合在微服务中以什么形态存在?另外对于一个微服务内的聚合数量是否有一些建议参考?谢谢
    
    
  • 莫离
    2020-01-31
    感觉一个聚合对应的就是传统架构里面的一个模块,这样理解对吗?想问下领域和聚合根应该是一对一的,是吗?

    作者回复: 聚合应该比模块还要小一些,它是一个比较小的功能集合,聚合内的对象可以独立完成聚合的逻辑,它也是可以独立部署为微服务的最小单位。领域模型里面可以包括多个聚合,一个聚合会有一个聚合根。所以一个领域模型至少有一个聚合根。

    
    
  • 兆哲
    2020-01-31
    老师 看到这里 感觉聚合很像是领域服务,但是差别在于,领域服务没有聚合根,不知道这样理解对吗?
    还有就是平时的业务场景发现,好像类型订单,之类的实体都是贫血模型,天生没有业务方法,不知道怎么应用DDD进行建模。希望老师能给一点提示。

    作者回复: 在设计的时候要实体采用充血模型,让实体要有业务行为,也就是实体通过自身的实体类方法来实现实体的业务逻辑,采用面向对象的设计方法。多个实体组合的业务逻辑用领域服务来实现。

     1
    
  • 很ok的火龙果
    2020-01-22
    “是否有独立的生命周期?是否有全局唯一 ID?是否可以创建或修改其它对象?是否有专门的模块来管这个实体。图中的聚合根分别是投保单和客户实体。” ——— 账户也有唯一ID,也可以创建并修改其他对象,账户我理解应该也需要专门的模块管理吧,为啥“账户”不是聚合根呢?

    作者回复: 账户在账户聚合内是聚合根。

    
    
  • 很ok的火龙果
    2020-01-22
    “是否有独立的生命周期?是否有全局唯一 ID?是否可以创建或修改其它对象?是否有专门的模块来管这个实体。图中的聚合根分别是投保单和客户实体。”
    
    
我们在线,来聊聊吧