- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我被要求在旧版Web应用程序中实施CQRS / Event来源模式,以准备将其从单块/面向状态的模型迁移到面向服务的分布式应用程序。
我对如何设计一个面向域的代码束有一些疑问,该束将使用新的事件源模型将紧密耦合到数据库的旧实体连接起来。
我做的第一件事是:
用诸如AggregateRoot,DomainEvent,Command,Handlers,Messaging,Eventstore,AggregateIds等类为CQRS / ES编写一个小的“框架”。
尝试将旧实体分组并“迁移”到一些聚合中,以将应用程序的所有历史和状态重构为EventSoourced聚合
在旧控制器中插入一些Commands调度程序,以使应用程序按原样工作,同时还可以在侧面提供新的CQRS / ES系统。
上下文:
旧版应用程序包含映射到数据库的多个实体,这些实体保存模型层。 (我们的领域是人力资源(人力)。
假设我们有这些现有实体:
具有各种字段和相关实体(OneToOne,OneToMany)的工作者,例如
名称
地址1-1
能力1-N
工人工作的社会,涉及各个领域和相关实体(OneToOne,OneToMany),例如
名称
地址1-1
小时
具有各种字段和相关实体(OneToOne,OneToMany)的合同,例如
地址1-1
1-1
社会1-1
文件1-N
第1-N天
小时
等等
从这个旧模型中,我设计了一个MissionAggregate,它具有:
db独立ID,例如UUID
一些值对象:地址,日期(它们在旧模型中是一个实体,在这里成为VO)
我还设计了一个具有字段和UUIDS的WorkerAggregate和SocietyAggregate,并在MissionAggregate中添加了:
对WorkerAggregate的UUID的引用
对SocietyAggregate的UUID的引用
就像我之前说的,我的目的是使旧版应用程序保持不变,而只是在CRUD控制器的方法中引入一些将Command调度到新CQRS系统的调用。
例如:
在bdd中刷新新创建的Contrat之后,我想向新的命令总线分派“ CreateMissionCommand”。
它针对适当的命令处理程序,该命令处理程序处理所有命令数据,将其传递给具有新UUID的新创建的Aggregate,并将“ MissionCreatedDomainEvent”存储在EventStore中。
DomainEvent用一个播放头AggregateId进行索引,并具有一个有效负载,该有效负载包含要应用于和构建MissionAggregate所需的字段。
与往常一样,在应用程序中创建的新Contract现在具有以前的生命周期,其中包含旧版应用程序对其执行的所有更新。但是我还需要将所有这些更改反映到相应的EventSourcedAggregate上,因此,每次应用程序中的数据库出现刷新时,我都会调度一个Command,该命令将旧版应用程序的“类似操作”转换为面向域/面向命令的模式。
总结工作流程是:
发生Crud旧操作并刷新合同实体上的某些更改
在控制器中的一行代码中,我将构建有必要字段(MissionAggregate的AggregateId ...我需要将其存储在某处,请参阅下一个问题)的命令调度到Domain命令总线,以便对现有的代码库非常低。
总线将命令传递给相应的命令处理程序
处理程序通过调用适当的Aggregate方法来加载聚合并应用更改
然后经过一些验证,聚合引发并存储适当的事件
我的问题和疑问(至少其中一些;)是:
我觉得我正在重写旧版应用程序的所有重要部分,它们之间具有实体之间相同的聚合关系,并且具有相同类型的验证,检查等。
在MissionAggregate中同时引用了WorkerAggregate和SocietyAggregate UUID意味着我也必须构建那些聚合(因此在刷新Worker和Society实体时,从旧版应用程序中调度命令)。我是否只能引用工人的实体ID和协会的实体ID?
我如何避免拥有一个不断增长的MissionAggregate?合同实体非常庞大,它具有大量不断更新的字段(小时,天,文档等)。如果我想存储所有这些事件,则需要有一个较大的MissionAggregate来反映所有这些更改;因此,我需要拥有大量的CommandHandlers,它们可以对我将要从旧版应用程序分派的所有add,update等命令做出反应。
根实体应该引用的聚集体有多“免费”?例如,合同实体需要在某个地方与其相关的任务集合相关联,例如当我想在遗留代码已刷新实体上的某些内容之后从应用程序分发Command时。在哪里存储这种关系?在实体本身中,在AggregateId字段中?在汇总中,我应该有一个ContratId字段吗?还是我应该在某处具有某种映射表,其中包含合同ID和MissionAggregate ID之间的关系?
过去该怎么办?我应该通过一个脚本来迁移所有现有数据,该脚本在所有历史数据上生成汇总和事件吗?
在此先感谢您的时间。
最佳答案
您面前还有一项艰巨的任务,让我们尝试分解一下。
最好将系统的这一新部分与传统代码库隔离开来,否则您将无所适从。
在项目中为这些新需求创建一个单独的层。从现在开始,我们将其称为“气泡”。这个气泡就像一个未开发的项目,具有自己的结构,依赖关系等。气泡和遗留物之间不会直接通信;通信将通过另一个专用的翻译层进行,我们将其称为“反腐败层”(ACL)。
访问控制列表
就像两个系统之间的API。
它将呼叫从气泡转换为遗留,反之亦然。其目的是防止一个系统损坏或影响另一个系统。这样,您可以保持彼此独立地构建/维护每个系统。
同时,ACL允许一个系统使用另一个系统,并重用逻辑,验证,规则等。
要直接回答您的问题:
我觉得我正在重写旧版应用程序的所有重要部分,它们之间具有实体之间相同的聚合关系,并且具有相同类型的验证,检查等。
使用ACL,您可以求助于调用验证并从旧代码中重用实现。这将使您有时间根据需要或尽可能多地重写内容。
但是,您可能不需要重写整个系统。如果您的目标是实施CQRS和事件源,并且可以通过保留大部分或部分旧系统来实现此目标,那么我会说您做到了。当然,除非目标之一是完全替代旧系统。否则,请保留;编写尽可能少的代码。
建议的工作流程:
将CQRS和事件源系统保持在泡沫中
不要将这些新框架带入传统
对ACL进行滞后控制器发出方法调用
ACL会将这些调用转换为命令并分派它们
任何事件都将被您的事件来源框架捕获
结果将保存到气泡数据库中
气泡的数据库可以是同一数据库中的不同架构,也可以是完全不同的数据库。但是您必须考虑同步,这是它自己的主题。为了降低复杂性,我建议在同一数据库中使用不同的架构。
在MissionAggregate中同时引用了WorkerAggregate和SocietyAggregate UUID意味着我也必须构建那些聚合(因此在刷新Worker和Society实体时,从旧版应用程序中调度命令)。我不能仅引用工人的实体ID和协会的实体ID吗?
我如何避免拥有一个不断增长的MissionAggregate?合同实体非常庞大,它具有大量不断更新的字段(小时,天,文档等)。如果我想存储所有这些事件,则需要有一个较大的MissionAggregate来反映所有这些更改;因此,我需要拥有大量的CommandHandlers,它们可以对我将要从旧版应用程序分派的所有add,update等命令做出反应。
您应该针对小型骨料。巨大的聚合可能会降低性能并导致并发问题。
如果您预计会有一个巨大的总量,那么最好重新考虑一下并尝试将其分解。询问哪些字段/属性一起更改-这些可能是不同的集合。
另外,在谈到CQRS时,通常会倾向于在系统中采用基于任务的处理方式。
考虑一下传统的Web应用程序,其中有一个巨大的页面,其中包含许多字段,当用户保存时,这些字段将全部发送到服务器。
现在,将它与现代Web应用程序进行对比,在Web应用程序中,用户在每个步骤中都更改一小部分数据。如果以这种方式考虑系统,则会发现那些较小的聚合。
PS。您无需为此重建接口。如果您的旧系统有那么大的页面,则可以在控制器中包含逻辑以检测更改了哪些字段并发出适当的命令。
根实体应该引用的聚集体有多“免费”?例如,合同实体需要在某个地方与其相关的任务集合相关联,例如当我想在遗留代码已刷新实体上的某些内容之后从应用程序分发Command时。在哪里存储这种关系?在实体本身中,在AggregateId字段中?在汇总中,我应该有一个ContratId字段吗?还是我应该在某处具有某种映射表,其中包含合同ID和MissionAggregate ID之间的关系?
集合表示概念整体。他们就像原子,不可分割的事物。您应该始终通过根实体ID引用聚合,而永远不要通过子实体ID引用聚合:从外部看,没有子代。
聚合应作为一个整体加载并作为一个整体持久存在。骨料少的另一个原因。
聚集可以由单个实体组成。或者它可以具有更多的实体和值对象,从而形成一个图,但是一个实体将被选作Root,并将保留对其子代的引用。子实体和值对象不应包含对其父代的引用。依赖性不是双向的。
如果合同是任务汇总中的一个实体,则合同不应引用其上级。
但是,如果您的合同和任务是不同的汇总,则它们可以通过其ID相互引用。
与过去有什么关系?我是否应该通过一个脚本迁移所有现有数据,该脚本会在所有历史数据上生成聚合和事件?
这是业务专家的问题。他们需要吗?如果他们不这样做,则不要仅仅为了实现它而实施它。考虑到成本和权衡因素,您所做的每个决定都应着眼于满足业务需求并为其产生实际价值。
有人说代码是一种责任,而不是资产,我在某种程度上表示赞同:您编写的每一行代码都需要测试和支持。不要编写任何不必要的代码。
另外,请查看此article about the Strangler Pattern,它显示了如何通过逐渐用新的应用程序和服务替换特定功能来迁移旧系统。
如果有机会,请在Pluralsight观看此课程(收费):Domain-Driven Design: Working with Legacy Projects。作者提出了处理此类任务的实用方法。
我希望这能给您一些见识。
关于domain-driven-design - 如何设计从面向CRUD的旧版应用程序到CQRS和事件源系统的桥梁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57326853/
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 9 年前。 Improv
我刚刚发现了这门语言,我想知道是否可以使用数据库制作基本的 CRUD 网络应用程序。 最佳答案 有 mysql 的库和 postgresql , 核心库提供了一个 web server支持 HTTP、
Symfony 4.0 发布后,不再支持 SensioGeneratorBundle .因此命令 php app/console generate:doctrine:crud不可用。 他们建议使用 M
在开发 Web 应用程序时,我通常会看到人们执行增删改查和同步 View 的两种方式。 这里是使用 ajax 的高级示例。 1-方法一 创建操作可能涉及 POST 请求,成功后只需执行另一个 GET
我已经成功地使用 Yii2 模型和 CRUD 生成器为我的网络应用程序获取了一些框架代码文件。特别是,CRUD Generator 声称已成功将其 View 文件创建到: /basic/views//
在我的项目中,我一直在使用 Django 的通用 CRUD View 来处理很多事情。我现在想开始迁移到 DJango 1.3 中基于类的新样式通用 CRUD View 。我没有发现这些文档有多大帮助
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题?通过 editing this post 添加详细信息并澄清问题. 7年前关闭。 Improve this
我希望标题不要太含糊,所以这里是: 我创建了一个 MySQL 数据库,其中存储了两个表:一个包含输入数据,另一个包含输出数据。 之后我编写了一个程序,连接到这个特定的数据库,从输入表中提取数据,解析它
我需要编辑我的实体以获得更多值。我已经用我之前的值生成了 crud。如何在编辑实体后通过应用程序/控制台重新生成 crud,以便它自动为其他值生成函数。 最佳答案 为此,您需要删除为此 crud 生成
因此,我仅使用 JavaScript 创建了一个简单的 CRUD 应用程序。现在,您可以将国家/地区添加到数组中并从数组中删除国家/地区。我希望能够编辑数组中的现有国家/地区,例如我想将“斯德哥尔摩”
我想让java中的一个类有一个可以与Hibernate配置交互并执行某些操作的方法,该方法被标识为ENUM(例如:读取,更新,添加,删除等) 方法参数应为(枚举操作、类 DTO、NamedQuery
我正在构建一个 React 应用程序,并使用 auth0 来登录/验证用户。 在使用 auth0 之前,我一直在对 API 进行 CRUD 调用来发布帖子。这又是在使用 auth0 之前、在我拥有用户
尝试使用 BlueJ 构建我的第一个 Java MySQL CRUD 应用程序。我可以运行该应用程序并将数据写入 MySQL 数据库。但是,当我运行搜索函数时,我得到了 Java .NullPoint
我正在试用 Microsoft Master Data Services,我想以编程方式将数据添加到数据库中。我开始获得模型/实体/成员结构,但我还不确定。如果您对此结构有很好的解释,请分享。 假设有
我正在尝试开发一个 Backbone Marionette 应用程序,我需要知道如何以最佳方式执行 CRUD(创建、读取、更新和销毁)操作。我找不到任何解释这一点的资源(仅适用于 Backbone)。
我已经根据文档和 medium article 模拟了与 Room 的多对多关系。 .使用这个@Relation,我可以从数据库中检索RecipeWithIngredients 或Ingredient
Closed. This question is opinion-based。它当前不接受答案。 想要改善这个问题吗?更新问题,以便editing this post用事实和引用来回答。 3年前关闭。
通过AngularJS通过REST进行CRUD操作的最佳实践是什么? 特别是这里的 Angular-Way 。我的意思是使用最少代码和最默认 Angular 设置来达到此目的的方式。 我知道$ res
我无法弄清楚我的更新功能。我能够从数据库中检索和删除,但我不知道如何更新。这对我来说是全新的,所以我很困惑。 .js 文件 //update user $("#btnUpdateUser").clic
我正在寻找一种对用户透明的 CRUD 操作后重新加载页面的方法。 实际上,在创建或删除之后,我必须重新加载页面才能显示我的操作。 我使用 api 来实现这个,当我将它与 json 文件一起使用时,它工
我是一名优秀的程序员,十分优秀!