问题标签 [dddd]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
2219 浏览

domain-driven-design - 聚合根中覆盖的实体如何保存在 DDD 中?

在阅读了很多帖子之后,我意识到如果一个概念/上下文存在聚合根,我们需要为整个概念/上下文建立一个存储库。

如果是这样的话,我认为内部实体不会有任何存储库。如果是这样,这些内部实体如何保存到数据库中?

我在聚合根目录下有许多内部实体。所以,想知道如果我需要在聚合根存储库下保存所有内部实体,它会变得臃肿。请建议在这种情况下可以做什么。

此外,我的内部实体将在持久性级别访问它们自己的每个表。如果我不允许以这种方式存储内部实体,请纠正我。

示例
考虑我有一家餐厅作为聚合根。它可以对名为 Review 的实体进行分组。评论存在于餐厅,没有评论就无法存在。

在这里,如果 Review 是一个内部实体,并且餐厅可能有许多评论,则评论将保存在单独的表中。但由于餐厅聚合根只有一个餐厅存储库,因此如何/在哪里处理保存评论。

0 投票
1 回答
207 浏览

domain-driven-design - 如何跨有界上下文传递(发布/订阅)域事件

开放主机服务是一种在上下文之间进行映射的方式,适用于通过 API 公开访问的情况。什么是表示上下文之间映射的好方法,您打算在其中发布/使用域事件?

0 投票
2 回答
223 浏览

domain-driven-design - 用于将数据同步到其他微服务的领域事件

我正在尝试更多地了解DDD并正在经历DomainEvents. 假设我们有三个微服务Service AService BService C

Service A有一个实体Foo定义如下:

并且 theService B是一项依赖于 from 的服务,emailFootheService C依赖于namefrom并且只要via a的值发生变化,数据就会从to和 toFoo复制。Service AService BService CFooBus

我遇到的有关领域事件的指南:

  1. 不要将多余的信息作为DomainEvent数据的一部分共享。
  2. 何时consuming BoundedContext知道Producing BoundedContext可能共享 ID,否则共享完整信息
  3. 不要DomainClasses用来表示事件中的数据
  4. 用于Primitive types数据Events

现在由于指导方针冲突而出现的问题:

这是否意味着当它们发生变化时我应该触发两个不同的事件FooNameChange并且FooEmailChanged只使用 theidupdated valueas 的一部分Event Payload

或者我可以只进行一次DomainEvent调用FooChanged并获取Foo序列化它的状态并触发事件。然后编写一个处理程序作为处理程序的一部分,该处理程序BoundedContext将获取数据并将其放在Bus订阅消息的任何服务上,并且单个服务根据Id附加的和事件 arg(更新的数据)。

0 投票
1 回答
116 浏览

domain-driven-design - 如何管理 DDD 中的两个耦合聚合?

我正在开发电动汽车充电站管理系统,连接了几个Charging Stations,我陷入了僵局。在这个领域中,我提出了 的聚合Charging Station,其中包括的内部状态Charging Station(是否已连接,其连接器的内部状态)。

它有一种UnlockConnector方法,为了准确尊重其名称(而不是贫血),它将请求发送到相应的Charging Station,因为它是我的域的中心,以了解 的Charging Station连接性并将请求发送到物理Charging Station

而且我想出了另一个聚合,它代表Charging Session用户和用户之间的Charging Station交互Connector。a 的创建Charging Session完全与Connector' 状态相结合,即如果Connector已经被用户解锁,则创建会话,如果Connector' 的能量流已停止,则已Charging Session结束。

不管它们如何耦合,Charging Session实体似乎不属于Charging Station聚合,因为它没有回答主要问题:当一个 Station 被删除时,它Charging Session的 s 是否也应该被删除?)还有,我什么时候会支付此会话中消耗的能量,它与 Station Aggregate Context 没有任何关系。

我想创建一个SessionCreator域服务,以确保当 aCharging StationConnector解锁时, aCharging Session也将被创建:

但是它只是感觉有点奇怪,并且不能完全满足其他不变量(当连接器的能量流停止时,它必须结束会话),我虽然也制作了一个监听事件的事件监听器StationConnectorUnlocked,但我只是不知道哪个是理想的方式。

0 投票
2 回答
792 浏览

domain-driven-design - 领域驱动设计:不同聚合的实体之间的引用

我正在尝试使用域驱动设计规则和模式开发我的第一个应用程序。

在我的业务场景中,我必须管理客户列表并跟踪发送到特定客户目的地的所有包裹。因此,按照规则,事实证明:

  • 客户是一个实体,也是一个 AggregateRoot。
  • 目的地是一个实体,它是客户的孩子(因为没有客户就没有意义)
  • 包是一个实体。它也是另一个 AggregateRoot,因为它是一个不同的事务边界,我使用 AddDestination(string destinationName ...) 方法开发了客户聚合,该方法负责为客户创建一个新的目标。

现在我需要开发 Package 类,我必须在其中维护对已运送包裹的目的地的引用。按照 DDD 规则,我不能直接引用子实体 id,因为我不能引用另一个聚合的子实体。

我需要做什么?

  1. 我是否必须使用目标所需的数据创建一个新的 ValueObejct 并公开它?(通过这种方式,我能够保留只能通过 Customer AggregateRoot 以书面形式访问的 Destionation 的封装和规则)。通过这种方式,外部类可以访问目标的字段并使用这些字段执行逻辑/检查,但不能更改目标的状态。
  2. 我是否必须添加一个 DestinationNumber 字段(在客户中渐进式),创建一个包含 CustomerId 和 DestinationNumber 的 ValueObject 并在 Package 聚合中使用它?
  3. ?

有人可以帮帮我吗?请详细说明回复,因为我想了解更多这种情况。

0 投票
1 回答
148 浏览

domain-driven-design - DDD:使用领域事件来保证不变量的一致性是否正确?我有其他选择吗?

在我的域模型中,我有一个项目实体(也是聚合根),它有产品实体作为子实体。我的域模型的不变量之一是我不能有两个产品具有相同项目的相同子代码(但如果项目不同则可以)。

我的产品由部分组成,这些部分也有类似的规则(同一产品中的每个部分都必须有唯一的代码),所以部分产品的子项,因为我需要确保该规则。产品的孩子也是我需要做的创建它的活动,因为我正在描述一个生产跟踪系统。

现在,活动可以有活动,可以分配到工厂区域等等。

基本上我所拥有的是所有实体都从项目开始只是因为我需要确保一个不变量(=业务规则)但不是最好的解决方案,因为每次我需要检索一个实体时我都需要填写所有项目(可以有2000 多种产品)。

我可以做些什么来拆分保留我的不变量,同时让我可以加载特定的活动(或产品),而无需在每次需要子实体时检索我的项目的所有产品?

我是否需要在多个 AggregateRoots 中拆分实体,在项目中维护 ProjectProductValueObject(字符串代码)列表并在 Aggregate 的构造函数中使用域事件来触发像 ProductCreatedEvent 这样的东西,它尝试使用 AddProduct 在我的项目中创建和添加新的 ProjectProductValueObject (ProjectProductValueObject product) 方法包含我的业务规则,如果不满足会抛出异常?这是否可以并符合 DDD 原则?

我还有其他选择吗?

0 投票
1 回答
131 浏览

domain-driven-design - 我应该如何处理多个聚合根交互

我读过这篇文章,在这篇文章中,Udi Dahan 谈到了多对多的关系。在该示例中,他解释说,在多对多关系的情况下,例如工作与工作板之间的关系,并考虑到将工作添加到工作板的有限上下文,聚合根将是工作板和您只需将工作添加到它。在评论部分,他还解释说,在不同的有界上下文中,作业将是聚合根,这是有道理的,因为作业可以在没有作业板的情况下存在,并且您可以对不影响作业的作业执行许多操作木板。我有一个类似的问题,但我似乎无法弄清楚这将如何解决。我有两个问题:

  1. 如果我们需要删除工作,看起来取决于工作是否已发布,我们需要单独删除工作或删除工作但也将其从板中删除,这意味着修改同一事务中的两个聚合根,但这段代码应该去哪里?域服务?
  2. 如果工作和工作板可以是两个不同的聚合,工作实体需要存在于两个上下文中,那么我们如何处理这个问题,只需创建两个具有重复数据的工作类?

更新 1:

所以这就是我正在处理的场景......我有一个路由应用程序,我有代表旅行请求的请求,我有路线,有停靠点,每个停靠点都有一个或多个请求。为了创建路由,我使用执行路由的外部服务,并将路由结果存储在路由表中。

问题是我不怎么建模这种关系,这里有一个用例来考虑,请求取消是一个过程,根据请求的状态和路由的状态可以导致不同的动作:

  1. 请求未路由(未分配给路由),只需取消请求即可。
  2. 请求被路由,路由被调度,然后取消请求,从路由中删除请求,并重新创建路由(使用外部库),因为删除请求可能会导致删除停止,所以我需要重新创建路线内部,它仍然是一个更新。
  3. 请求被路由,路由在途中,然后我将请求标记为未显示,并更新路由。

所以起初我虽然请求、路由和路由表是单独的聚合,但这意味着我需要在同一个事务中修改多个聚合(通过使用服务或使用域事件)我不确定如果创建更高级别的聚合根(带有请求、路由数据和最终路由数据)是有意义的,因为我不会总是拥有所有数据来加载聚合根,事实上大多数时候我会有它的一部分,要么是 1 个请求,要么是具有多个请求的路由。我愿意接受建议,因为我似乎无法解决这个问题。

更新 2:因此添加更多上下文,我将向实体添加更多细节:

  • 请求,它代表一个旅行请求,它有几个具有定义工作流的状态
  • 路由,它有一个定义了转换的定义工作流,有一个停靠点的集合,每个停靠点都有一个有效负载的集合,每个有效负载都有一个请求 id,(Route -> stops[] -> payloads[]-> requestId)
  • 路由,它代表调用路由引擎的结果,它基于您要路由的一系列请求将生成路由/路由

所以这个实体存储在一个 mongodb 集合中,让我们看看用例:

UC - 请求取消我可以仅使用请求 ID 取消请求,但根据请求的状态,我可能还需要修改路由。1 请求未路由,因此使用请求 id,我获取请求并取消它,这很简单。2 请求被路由,并且路由被调度,在这种情况下,我需要获取请求,然后获取路由以及与该路由绑定的所有请求(它包括触发命令的请求),然后删除有效负载(以及与请求相关联的站点(如果它只有一个有效负载),因为此选项可以更改站点,我需要使用外部 api(路由引擎)重新创建路由并在路由表中创建一个条目。3 Request is Routed,Route是en-route,这种情况下我需要获取request,

UC - 启动路由一旦创建并安排好路由,我就可以启动它,这意味着修改路由状态、停止状态、有效负载状态以及相关请求的状态。

正如您在用例中看到的那样,路由 - 请求和路由表是非常密切相关的,所以起初虽然有单独的聚合根,请求是一个 AR,路由是一个 AR,路由是一个 AR,但这意味着修改同一笔交易中有多个 AR。现在让我们看看拥有所有实体的 AR 会是什么样子

所以让我们再看看 UC UC - Request Cancellation

  1. 在这种情况下,我只有 1 个请求数据,所以我必须将 routeData 留空,这听起来不对
  2. 在这个我有路由和请求数据所以我很好
  3. 在这个我有路由和请求数据所以我很好

这里的主要问题是,一些操作可以在 1 个请求上完成,而其他一些操作将在路由上完成,而其他一些操作将在两者中完成。所以我不能总是通过 ID 获得聚合,或者我不能总是用相同的 ID 获得它。

0 投票
0 回答
154 浏览

domain-driven-design - 是否有交互式主动工具可以对 DDD(领域驱动设计)中的任何 IT 项目进行建模?

是否有交互式主动工具可以对 DDD 中的任何 IT 项目进行建模?

我看过 eventmodeling.org、eventstorming,我看过所有用于现场研讨会的伟大技术(如果没有现场,他们会使用 miro),但它们仍然是“手动”工具。

是否有任何工具可以指导我识别限界上下文、聚合等?特别是如果我是 DDD 新手?

而且我知道每个领域都是不同的,但是由于剔除它的过程总是相同的,也许这样的工具真的可以提供帮助。

0 投票
1 回答
41 浏览

microservices - 在 DDD 中设计排行榜分数

围绕这个问题有两个实体,主要是

  1. 排行榜 - 包含关于类型(最低优先/最高优先)、描述、名称等的信息。
  2. 得分 - 玩家提交的得分值,其中包含玩家详细信息和得分值

用例:

  1. 我们需要获取前 10 名的得分
  2. 对于每月排行榜,我们需要找到前 3 名

域规则:

  1. 玩家可以提交任意数量的分数
  2. 排行榜排名需要基于排行榜中定义的类型(最低/最高)

对于这样一个系统

  1. 排行榜和分数有1对多的关系
  2. 分数需要有关于玩家信息的信息(这是一个单独的聚合根并且在不同的边界上下文中)

如何在 DDD 中设计它?

场景 1: 排行榜是否将是聚合根并且分数将通过排行榜聚合根添加(对于每个分数)?

查询:

  1. 在这里,没有排行榜,分数没有意义,也没有域规则坚持通过排行榜聚合根添加分数。这实际上是一个两难境地,如何处理?

  2. 如何获取玩家详细信息以输入分数?我是否需要在域服务中获取玩家详细信息并在添加分数时提供排行榜聚合根?

场景 2:Leaderboard 和 LeaderboardScore 是两个不同的聚合根。

查询:

  1. 在计算排名时,我们需要从分数聚合根中获取分数并从排行榜中输入信息并完成用例?

  2. 这里的大部分用例服务代码需要在域服务或应用程序服务中?