gpt4 book ai didi

design-patterns - 带有 REST API 的 CQRS 组件角色和职责

转载 作者:行者123 更新时间:2023-12-04 08:44:10 25 4
gpt4 key购买 nike

关于带有 DDD 的 CQRS 以及每个组件的构成,有很多意见。我还没有开始研究事件溯源,所以下面的列表不包括任何与此相关的内容。尽管深入了解 ES 会很有趣。

到目前为止,我有以下具有相关职责的组件(见下文)。我在以下几点内联了一些问题。

REST 端点/应用程序

  • 接收来自用户/ui/etc的请求
  • 构建和调度相关Command
  • 如果命令需要来自其他有界上下文的值,则执行正确实例化命令所需的相关 Finder 调用(例如,订单需要用户 ID)
  • 在 GET 的情况下:相关的 Finder 被称为
  • Finders 位于应用程序的这个级别。限界上下文写入端(命令处理程序、聚合、工厂、域服务等)不应调用 Finders。这将保持封装,并且通过将所需的数据(而不是完整的 DTO)传递到命令中,它成为一个适度的反腐败层。
  • 例如:

  • AggregateId orderId = AggregateId.get();
    AggregateId userId = finder.findUserAggregateIdByEmail(email);
    dispatcher.fire( new CreateOrderCommand( orderId, userId, orderItems ) );

    命令
  • 通过调度命令对域进行更改
  • 命令是不可变的,包含有界上下文改变其状态或抛出异常所需的数据
  • 可以在创建对象时验证命令输入,以避免发送无效命令
  • 例如:new CreateOrderCommand( orderId, userId, orderItems );

  • 命令处理程序
  • 处理程序可以成功应用命令或引发异常
  • 每个命令只能有一个命令处理程序
  • 处理程序将加载或创建聚合根(存储库或聚合工厂)
  • 处理程序会将命令应用于聚合根
  • 处理程序处理存储库
  • 不应该触发命令(在它的有界上下文之内或之外)
  • 命令处理程序是否应该调度事件?例如成功保存到数据库后?或者这仅仅是聚合的责任?

  • 骨料厂
  • 封装正确初始化聚合根所需的逻辑
  • 工厂可以访问仓库
  • 工厂是否应该访问域服务?
  • 例如:factory.createOrder( orderId, userId, orderItems );

  • 聚合根/聚合
  • 包含域逻辑、状态和行为
  • 负责调度Events
  • Aggregate Root 封装了对 Aggregates 的访问
  • 聚合根应该有一个唯一标识它的 ID
  • 不应与外部服务(事件发布者除外)交互
  • 例如:order.cancel();

  • 域名服务
  • 这包含不太适合聚合根的内容
  • 域服务可以与哪些组件交互?
  • 域服务是否应该触发命令/事件?
  • 例如:不确定在这里使用什么,上面的第一点充其量是模糊的。大多数行为都很好地位于聚合中,或者可以通过 Sagas/事件/命令来实现。什么是有效的例子?

  • 存储库
  • 负责加载/保存/更新/等我们的聚合
  • 例如:repo.load(orderId);

  • 事件
  • 表示聚合中发生的事情(或命令处理程序等,如果它们也可以触发事件)
  • 事件是不可变的
  • 系统中的其他有界上下文可以使用事件来做出决策
  • 例如:new OrderCancelledEvent( orderId );

  • 事件处理程序
  • 对发生的事件使用react
  • 在相同或不同的有界上下文中,单个事件可以有多个事件处理程序
  • 可以与基础设施服务交互:OrderCancelled => OrderCancelledHandler => EmailService.sendEmail()
  • 可以触发新命令
  • 可以与 Finders 交谈
  • 当事件处理程序触发命令、与 Finders 对话并与基础设施交互时,它在本质上类似于 Saga(或 REST Enpoint 行为)。除了它是对单个事件而不是一系列事件的 react 。

  • 佐贺
  • 维护跨相同或多个有界上下文(坐标)的业务流程
  • 接收事件
  • 维护链/事件集的状态
  • 通常状态是持久化的
  • 可以设置超时以检查/更改状态(可以有时间概念)
  • 状态可能有副作用,例如:发出命令、与 Finders 交谈、与基础设施服务(例如电子邮件)交互
  • 例如:
    等待 OrderShipped 和 OrderReceived 事件 => 触发 CancelOrderCommand
    等待订单取消 => 取消订单取消电子邮件

  • 查找器
  • 用于检索上下文的读取模型
  • 一般返回数据传输对象 (DTO) 类型的对象
  • Finder 不应该出现在我们的应用程序的写入端(较少耦合)
  • 单一(读+写)规范化数据库模型:Finder 可以调用其他 Finder(跨上下文)来满足嵌套对象
  • 读取特定的非规范化数据库模型:Finder 将在一次数据库调用中获取所有数据
  • 例如:finder.findOrdersOnDate( date );

  • 基础设施服务
  • 处理基础设施:数据库访问、发送电子邮件、消息队列等

  • 问题

    这是组件与职责的准确总结吗?
    缺少什么,应该移动什么?
    我可以用相关答案更新列表。

    最佳答案

    就像你说的,外面有很多意见,你需要过滤它们,因为大多数时候人们在没有任何经验的情况下发表意见。 CQRS 是一个很大的话题,所以我认为如果没有之前的经验,你不应该完全进入 DDD 和 ES。服务应该被很好地包含并具有明确定义的边界,如果您遵循这些原则,您将能够在您的域中拥有不同的实现,所以现在从 CQRS 开始,并在您掌握 CQRS 后将 DDD/ES 添加到以下服务中。

    我建议你开始构建架构的 CQRS 部分,一个用于命令的网关和一个用于查询的网关,因为这很常见,而且需要做出很多决定:

  • 休息API
  • 消息合约/验证
  • 读取模型
    ...

  • 并开始以更传统的方式实现您的服务,无需 DDD,只需使用存储库模式。当您开始感到自信时,也许您可​​以在聚合方面跳入 DDD,然后再跳到 ES。您始终可以在稍后阶段更改初始服务。

    我的建议是不要尝试一下子做所有事情,因为你会失败;我已经看到它发生很多次了。

    For example: Wait for OrderShipped and OrderReceived events => fire CancelOrderCommand Wait for OrderCancelled => fire order cancelled email



    Sagas 不应发布事件(saga 模式)、saga 聚合事件和提交命令。像 NServiceBus 这样的框架允许 sagas 发布事件的事实无济于事,所以要注意。

    Single (read+write) Normalized Database Model: the Finder can call other Finders (across contexts) to satisfy nested objects



    您希望在阅读模型中拥有哪些其他上下文?

    Infrastructure Services


    Deals with infrastructure: db access, send emails, message queues, etc

    不确定你的意思,但它看起来肯定不正确。消息队列还是数据库服务??

    关于design-patterns - 带有 REST API 的 CQRS 组件角色和职责,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23234663/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com