到目前为止,我有以下相关责任的组件(见下文).我在下面的几点中概述了一些问题.
REST端点/应用程序
>接收来自用户/ ui / etc的请求
>构建和发送相关命令
>如果命令需要来自其他有界上下文的值,则执行正确实例化命令所需的相关Finder调用(例如,Order需要用户ID)
>在GET的情况下:调用相关的Finder
> Finder坐在应用程序的这个级别.有界上下文写入方(命令处理程序,聚合,工厂,域服务等)不应该调用Finders.这将保持封装并通过仅将所需数据(而不是完整的DTO)传递给命令,它将成为适度的反腐败层.
>例如:
AggregateId orderId = AggregateId.get();
AggregateId userId = finder.findUserAggregateIdByEmail(email);
dispatcher.fire(new CreateOrderCommand(orderId,userId,orderItems));
命令
>通过调度命令对域进行更改
>命令是不可变的,包含有界上下文改变它的状态或抛出异常所必需的数据
>可以在创建对象时验证命令输入,以避免发送无效命令
>例如:new CreateOrderCommand(orderId,orderItems);
命令处理程序
>处理程序可以成功应用命令或引发异常
>每个命令只能有一个命令处理程序
>处理程序将加载或创建聚合根(存储库或聚合工厂)
>处理程序将命令应用于聚合根
>处理程序处理存储库
>不应该触发命令(在其有界的上下文中)
>命令处理程序是否应该调度事件?例如,成功保存到数据库后?或者这仅仅是Aggregate的责任?
聚合工厂
>封装正确初始化聚合根所需的逻辑
>工厂可以访问存储库
>工厂应该访问域名服务吗?
>例如:factory.createOrder(orderId,orderItems);
聚合根/聚合
>包含域逻辑,状态和行为
>负责派遣活动
> Aggregate Root封装了对Aggregates的访问
> Aggregate Root应具有唯一标识它的ID
>不应与外部服务(事件发布者除外)交互
>例如:order.cancel();
域名服务
>这包含不太适合聚合根的内容
>域服务可以与哪些组件进行交互?
>域服务是否应该触发命令/事件?
>例如:不确定在这里使用什么,上面的第一点充其量是模糊的.大多数行为很好地存在于Aggregate中,或者可以通过Sagas / Events / Commands实现.这里有什么有效的例子?
知识库
>负责加载/保存/更新/等我们的聚合
>例如:repo.load(orderId);
事件
>表示在聚合(或命令处理程序等,如果它们也可以触发事件)中发生的事情
>事件是不可改变的
>系统中的其他有界上下文可以使用事件来做出决策
>例如:new OrderCancelledEvent(orderId);
事件处理程序
>对发生的事件做出反应
>在相同或不同的有界上下文中,单个事件可以有多个事件处理程序
>可以与基础设施服务进行交互:OrderCancelled => OrderCancelledHandler => EmailService.sendEmail()
>可以触发新命令
>可以与Finders交谈
>当事件处理程序触发命令,与Finder对话并与基础结构交互时,它在本质上与Saga(或REST Enpoint行为)类似.除了它是对单个事件的反应,而不是对一系列事件的反应.
冒险故事
>维护一个跨越相同或多个有界上下文(坐标)的业务流程
>接收活动
>维护链/事件集的状态
>通常状态是持久的
>超时可以设置为检查/改变状态(可以有时间概念)
>国家可能有副作用,例如:发射命令,与Finder交谈,与基础设施服务交互(例如电子邮件)
>例如:
等待OrderShipped和OrderReceived事件=> fire CancelOrderCommand
等待OrderCancelled =>消防订单取消电子邮件
发现者
>用于检索上下文的readmodel
>通常返回数据传输对象(DTO)类型对象
>在我们的应用程序的写入方面不应找到Finder(耦合较少)
>单(读写)规范化数据库模型:Finder可以调用其他Finder(跨上下文)来满足嵌套对象
>读取特定的非规范化数据库模型:Finder将在一次数据库调用中获取所有数据
>例如:finder.findOrdersOnDate(date);
基建服务
题
这是组件与责任的准确总结吗?
缺少什么,应该移动什么?
我可以用相关答案更新列表.
解决方法
我建议你这样开始构建你的体系结构的CQRS部分,一个命令的网关和一个查询的网关,因为这是常见的,只是因为有很多决定要做:
> Rest API
>消息合同/验证
>阅读模型
…
并且在没有DDD的情况下以更传统的方式开始实现您的服务,只使用存储库模式.当你开始感到自信时,也许你可以在聚合方面进入DDD,然后再转向ES.您可以随时更改初始服务.
我的建议是不要试图一次性完成,因为你会失败;我以前见过很多次.
For example: Wait for OrderShipped and OrderReceived events => fire CancelOrderCommand Wait for OrderCancelled => fire order cancelled email
Sagas不应该发布事件(传奇模式),传奇聚合事件和提交命令.像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
不确定你的意思,但肯定看起来不对.消息队列或数据库服务??