1. 首页
  2. 生活常识
  3. ddd是什么意思(迁移过程中可能存在的疑问)

ddd是什么意思(迁移过程中可能存在的疑问)

简介:关于ddd是什么意思(迁移过程中可能存在的疑问)的相关疑问,相信很多朋友对此并不是非常清楚,为了帮助大家了解相关知识要点,小编为大家整理出如下讲解内容,希望下面的内容对大家有帮助!
如果有更好的建议或者想看更多关于生活常识技术大全及相关资讯,可以多多关注茶馆百科网。

一.前言

随着版本的不断迭代,功能变得越来越复杂,系统的维护和功能迭代变得越来越困难。前任领导问我是否可以对架构做些什么,并将架构迁移到DDD。哈,哈,哈,哈,哈,哈,哈,哈,哈,哈,哈,哈,哈。说实话,我是从去年在大厂的一些朋友那里开始了解DDD的。我也不时地阅读相关的文章和开源项目,但我从来没有机会在我的实际工作中实现它。这是一个开始练习的好机会。

由于本文的重点是如何在MVC三层体系结构中迁移DDD,因此本文将首先简要介绍DDD的概念(详细的领域概念不会展开太多),然后对MVC三层体系结构向DDD的迁移方案提出建议。如果有什么错误,请指出来,共同进步。

我特别要感谢lilpilot就DDD降落方案提出的宝贵意见。

[01:10 . 1010]相信了解DDD的同学都听过网上那种官方介绍:

一种被领域专家、设计人员和开发人员理解的通用语言,作为相互通信的工具.这多少有点抽象。我听到你说的了,哈哈哈。在我看来,在MVC三层架构中,在我们开发功能之前,我们先获得需求并解释需求。通常第一步是设计表结构,在逐层设计上层dao、服务、控制器。针对产品或用户的需求进行一层自我理解转换。

众所周知,人才是体制中最大的漏洞。

经过这么多层转换后的用户需求被提出,尤其是研发需求在数据库结构的层转换后,业务向主观假设行为转变。业务边界一旦模糊,就没有得到充分考虑。大量的逻辑补充堆积到代码层实现上,变得越来越难以维护,到处if/else,传说代码都一样***。

DDD所要做的就是

消除信息不对称的传统MVC三层架构采用自底向上的设计方法进行逆向设计,面向业务,自顶向下的业务领域划分来分割大型业务需求,分而治之这里你可能对DDD和通用MVC架构的区别有些模糊。这里以电子商务订单场景为例。假设我们现在想要下一个电子商务订单来提出订单需求。它涉及用户选择商品、下订单、支付订单以及在用户下订单时发送订单。

在MVC架构中,我们通常在分析业务需求后,开始设计表格结构,如订单表、付款表、商品表等。然后编写业务逻辑。这是第一个版本的要求。当函数迭代饥饿时,我可以在付款后取消订单。如果我们退货或更换订购的货物,是否需要重新添加清单?随着功能的迭代,代码不断堆积。

在DDD体系结构中,我们首先划分了业务边界。这一切的核心是秩序。那么订单就是该业务领域中聚合逻辑的体现。付款,项目信息,地址等都围绕着订单和。在确定了订单本身的属性之后,地址只是属性的体现。一旦您建立了订单的领域模型,逻辑边界和仓储设计将紧随其后。

二.DDD是什么

面向对象设计,数据行为绑定,告别贫血模型降低复杂性,分而治之的优先领域模型,而不是切割数据和行为准确传达业务规则,业务优先代码设计通过边界划分简化复杂的业务领域,帮助我们设计清晰的领域和应用边界,可以轻松实现统一的业务和技术架构演化领域知识共享,提高辅助效率,增加可维护性和易读性,延长软件生命周期,在平台基石上

2.1.DDD简介

战略设计:有限上下文,通用语言,子领域

战术设计:聚合、实体、值对象、存储库、领域服务、领域事件、模块

有界上下文是领域模型存在的显式语义和上下文边界。在边界内,通用语言中的所有术语和短语都有特定的含义。

通用语言是一种简单、清晰、准确地描述业务含义和规则的语言。

将有界上下文分开。边界是领域的边界,上下文是语义环境。通过有界的领域上下文,我们可以在统一的领域边界内用统一的语言进行交流。

域是问题空间,有界上下文是解空间

2.2.为什么要用DDD

防腐层:简称ACL,集成了两种上下文。如果两边状态良好,可以引入防腐层作为两边的翻译,可以隔离两边的领域模型。

实体=唯一的身份+可变性[状态+行为]

当你只关心一个对象的属性时,它可以被用作值对象。我们需要将值对象视为不可变对象,不给它们任何标识,并尽量避免与实体对象相同的复杂性。

价值对象=以对象形式表达的价值,以表达特定的固定概念。

聚合是域对象的显式分组,旨在支持域模型的行为和不变性,同时充当一致性和事务边界。

我们将高度相关的、一致的生命周期实体和价值对象集合在一起。

2.3.DDD术语介绍

聚合的根实体,最具代表性的实体

当某些逻辑不属于实体时,可以将其取出并放入域服务中。理想情况下,不存在域服务,如果域服务没有得到正确使用,它将慢慢演变回以前的情况,即所有逻辑都在服务层中。

可以使用域服务的情况:

执行重要的业务操作来转换域对象并计算多个域对象作为输入参数,从而产生单个值对象

2.3.1.限界上下文与通用语言

是对聚合的管理,存储库位于域模型和数据模型之间,主要用于聚合的持久化和检索。它将领域模型从数据模型中分离出来,这样我们就可以专注于领域模型,而不必担心持久性。

我们将当前未使用的域对象从内存持久化到磁盘。当当天晚些时候需要再次使用域对象时,根据键值在数据库中找到该记录,然后将其恢复为域对象,以便应用程序可以继续使用它。这就是领域对象持久化存储的设计思想

2.3.2.上下文组织和集成模式

职责是创建一个完整的聚合

工厂方法工厂类领域模型中的工厂

将创建复杂对象和聚合的责任分配给单个对象,该对象不负责域模型,但它是聚合的域设计的一部分,我们应该立即创建整个聚合,并确保满足其不变条件,并且工厂只创建模型。包含工厂方法的聚合根的主要职责是完成其聚合行为。在聚合上使用工厂方法是表达公共语言的更好方式,而公共语言不是通过使用构造函数来表达的

聚合根中的工厂方法代表了领域概念,即工厂方法可以在域服务中提供工厂的保护措施

在集成有界上下文时,域服务作为工厂域服务的接口放置在域模型中,实现放置在基础设施层

2.3.3.实体

是聚合的管理,存储库位于域模型和数据模型之间,主要用于聚合的持久化和检索。它将领域模型从数据模型中分离出来,这样我们就可以专注于领域模型,而不必担心持久性。

我们将当前未使用的域对象从内存持久化到磁盘。当当天晚些时候需要再次使用域对象时,根据键值在数据库中找到该记录,然后将其恢复为域对象,以便应用程序可以继续使用它。这就是领域对象持久化存储的设计思想

[

2.3.4.值对象

]域事件是域模型中极其重要的一部分,表示域中发生的事件。忽略不相关的领域活动,同时指定领域专家想要跟踪或想要得到通知的事情,或者与其他模型对象中的状态更改相关联的事情

域事件=事件发布+事件存储+事件分发+事件处理。

例如,下订单后,用户需要增加积分和礼券。如果你以瀑布方式编写代码。一个逻辑调用,那么不同的用户,礼物不同的东西,逻辑就会变得又臭又长。这里更好的方法是,在用户成功下订单之后,发布域事件,积分聚合和优惠券聚合监视订单发出的域事件以进行处理。

:

2.3.5.聚合

2.3.6.聚合根

严格分层架构:一层只能与直接定位的下一层耦合。

松散分层架构:允许上层与任何下层耦合

依赖倒置原则

高级模块不应该依赖于低级模块;两者都应该依赖于抽象

抽象不应该依赖于实现细节;实现细节应该取决于接口

简单地说,它是面向接口的编程。

根据DIP原则,域层不再依赖于基础设施层。基础设施层通过实现注入持久性来解耦域层。使用依赖注入原理的新分层架构模型是这样的:

从上到下

第一层是用户交互层。Web请求、RPC请求、mq消息和其他外部输入被视为外部输入请求,可以将其修改为内部业务数据。

第二层是业务应用层。与MVC中的服务不同,服务存储了大量的业务逻辑。然而,在应用程序服务的实现中(就功能点而言),它负责编排、转发、验证等。

第三层是域层,聚合根是其中最高的人。核心逻辑体现在聚合根(拥塞模型)中。如果当前的聚合根不能处理当前的逻辑,需要其他聚合根的配合,则在聚合根之外封装一层域服务来实现该逻辑。当然,理想情况下不存在域服务。

第四层是基础设施层,它为其他层提供技术实现支持

我相信您在这里还看到了应用程序服务层直接调用存储库层的一行。这条线是什么意思?

领域模型的建立是为了控制数据添加、删除和修改的业务边界。对于数据查询,不同的报表、不同的页面需要显示聚合的数据,没有很强的业务域,所以通常采用CQRS模式来处理查询逻辑。

对于每个外部类型,都有一个与之对应的适配器。外部接口通过应用层接口与内部接口进行交互。

对于右边的端口和适配器,我们可以将存储库视为持久适配器。

当前位置修改对象状态的方法是Command,不应该返回数据,并且声明为void。对象上返回数据的方法是Query,不应该通过直接或间接的方式修改对象状态。聚合有一个Command方法,没有Query方法。存储库只有add/save/fromd方法。域模型分为两个部分,命令模型(写模型)和查询模型(读模型)。客户端:web浏览器、桌面应用程序等。查询处理器:一个简单的组件,它只知道如何执行对数据库的基本查询。查询处理器并不复杂,可以返回DTO或其他序列化的结果集。不反映域行为、仅用于数据显示客户端和命令处理器聚合的非规范化数据模型是一种具有良好设计的契约和行为的命令模型,将命令与相应的契约进行匹配很简单,事件订阅者更新查询模型以最终一致地处理查询模型

2.3.7.领域服务

着陆指南与实践:DDD着陆的事件驱动模型

事件驱动的体系结构可以集成到集成良好的六面体体系结构中,或者集成到传统的分层体系结构中。在长时间的处理过程中,管道和过滤器可以主动拉取状态检查:定时器与完成事件之间的竞争状态可能导致被动检查失败,接收到事件后检查状态记录是否超时。问题:如果由于某种原因没有得到一个事件不过期,事件源发布至少一个域事件总代表的每个命令操作的执行操作,每一个域事件将被保存到事件存储和总从存储库中检索时,它会重建总基于事件发生聚合,事件是重播在相同的顺序。聚合快照:存储聚合事件发生时的缓存状态。为了减少重播事件所需的时间:EventStorming是一组Workshop方法。DDD比EventStorming早了10多年,EventStorming并不是专门为DDD设计的,而是一种协作的、基于事件的方法,通过回顾系统的全图来快速分析和建模复杂的业务领域。

对于旧系统中的业务逻辑,按照上述方法划分业务逻辑聚合

比如,电商商城场景下的购车过程事件风波

2.3.8.应用服务

事件风暴结束业务汇聚确定后,需要进行场景划分和层次划分

当前位置在我们的日常代码中使用Repository模式是一件简单但有益的事情。最大的好处是,您可以与底层完全分离,从而允许业务的顶层快速发展。

以当前的逆模型为例,现有

OrderDOOrderDAO可以通过以下步骤逐步实现Repository模式:

生成Order实体类,初始字段可以与OrderDO一致生成OrderDataConverter,用MapStruct基本2行代码完成写单元测试,确保Order与OrderDO之间的转换100%正确生成OrderRepository接口和实现;使用单个测试来确保OrderRepository是正确的,将使用OrderDO的代码更改为Order,并在代码使用OrderDAO的地方使用OrderRepository,以确保业务逻辑的一致性。需要注意的是,目前我们使用的mybatis和dao操作包含业务含义,正常的存储库不应该有这样的方法,目前存储库中包含业务含义的方法都只是兼容的方案,最终状态会被淘汰。

极端的DDD倡导者只要求存储库中的save和byId聚合方法。这当然取决于实际的业务场景,但是建议只保留这两个方法,其他业务需求的查询聚合方法放在单独的queryRepository中,用于不同的数据查询聚合和页面数据显示。确保用于添加、删除或修改数据的条目是唯一的

[

2.3.9.工厂

]思路与repository一致,以调用payApi为例:

在域中创建新的适配器包创建新的PayAdapter接口定义适配器在基础架构中的实现,对内部模型和外部模型进行转换,调用支付接口,返回到内部模型更改原来业务中rpc被调用到适配器的地方,对rpc和适配器进行单次测试比较,确保正确性

2.3.10.资源库【仓储】

也符合六角形架构的思想;并为域中的mqProducer、JsonUtil和其他技术组件定义接口。在基础设施实现中,替换步骤类似于适配器。

2.3.11.事件模型

如果是有能力链的项目,可以申请能力链的服务。如果原始服务中的业务逻辑是混合的,甚至参数组装也包含在服务中。因此,有必要将逻辑放入聚合根中。不能完全包装当前的聚合根,以防止它在域模型中反映出来。在应用程序服务层是能力链的体现。

2.4.DDD架构总览

能力链项目,定义命令、查询包,通过能力链来体现command、query,包括CommandService继承、QueryService继承、CommandPo继承、QueryPo继承

在应用程序命令、查询包、参数和类名中定义的非链项必须反映CQRS。

重新设计可能与现有模型不同的聚合和实体。如果模型没有不同,则直接将功能点中的逻辑转移到实体。

不要调用存储库的业务意义方法,而是用保存和删除业务意义方法代替它们。在这种情况下,根据子域的选择,考虑用jpa替换mybatis。如果使用jpa,可以消除dao层。此时,原始业务中的大多数类都已迁移。

在迁移的过程中,肯定有或多或少不清楚的地方,在这里我分享一下我在迁移过程中遇到的问题。

1. 域服务和应用程序服务的区别

应用程序服务:将其理解为各种方法的编排,它不处理任务业务逻辑,例如订单号更改,从而导致价格更改。此逻辑包含在聚合根中,应用程序服务仅负责调用。

域服务:聚合不能完全处理这个逻辑,比如支付步骤。订单聚合不能进行支付,因此将域服务置于订单聚合的第一层,支付逻辑在域服务中实现。应用程序服务调用域服务。

2. 聚合根定义的业务边界是什么?

无表结构的数据用于业务逻辑划分,一个业务主体用于一块业务。例如,订单涉及商品、送货地址、送货地址、个人信息等。根据实体和值对象在聚合中定义。

3.当命令修改聚合时,它与其他关联表相关联。关联表是否是聚合表

关联表不是聚合,它们是值对象

4. 是否必须将适配器用于应用程序服务层的rpc调用

是的,必须使用它来掩盖外部依赖对当前业务逻辑的影响。假设您现在需要调用rpc接口,返回100个字段,并且希望获取其中的50个。过了一段时间,调用方更改接口逻辑的返回,数据包含在实体中。你称之为这个界面的地方的数量,变化很大。但是,如果您有一个适配器层,则可以定义业务所需的数据结构,而业务的其余部分不需要担心它。一个全新的适配器可以将您需要的数据从rpc加载到它。

5. 如果不能单独处理聚合根的内部逻辑,是否可以将其放入域服务中调用聚合根的其他域服务或应用服务,以业务强绑定的形式加入?如果聚合根的内部逻辑需要调用服务服务或仓库,应该怎么做?

您可以这样做,但是逻辑需要尽可能地内聚。

6. 事件通知方式。例如,如果它是强绑定的,那么它是否仍处于此模式,或者是否所有与聚合根无关的逻辑都将被通知

强依赖形式的逻辑编排,例如当订单依赖于支付结果进行聚合修改时的应用程序服务编排。订单支付后,发送优惠券、积分等弱耦合方式到事件通知模式。

7. 聚合根、PO、DTO和VO的极限

Po是与数据库表结构的一对一对应。

dto是数据载体,是只加载数据的贫血模型。

Vo是dto结构不满足前端表示要求时的封装。

聚合植根于一个或多个pos中的数据,不仅仅是pos的组合,还包括值对象数据、拥塞模型和内聚核心业务逻辑处理。

8. 查询逻辑要打开单独的存储库,也可以在聚合根存储库中,以什么为基础

建立一个单独的仓库。聚合根的仓库应该是聚合根的查询结果和保存参数,但是业务查询可能是多样化的,呈现给前端的数据可能不是由聚合根的字段组成的,而且查询不会对数据库造成不可逆的后果,所以查询逻辑处理是单独设置的,采用CQRS模式。

9. 返回的结果数据由多个接口组成。接口是否直接在应用服务层进行组合

不需要,您需要定义一个汇编类来分别处理各种依赖于外部的数据。

10. 是否删除,插入,更新所有方法?

删除方法是单独处理的,您可以添加删除方法,而插入和更新方法理论上需要相同。

11. 如果查询逻辑涉及到修改聚合根怎么办

简单的查询逻辑直接通过仓库,复杂的逻辑通过应用服务,在应用服务中对聚合根数据进行修改。

12. 在哪里存储逻辑服务

如果这种逻辑仅由一个聚合使用,则将其放置在相应的域服务中,如果逻辑处理由多个聚合使用,则将其定义为作为实用程序类的单独服务。

当然,并不是所有的业务服务都适合DDD架构,DDD适合产品化、可持续迭代、业务逻辑复杂的业务系统,中小型系统和团队不建议使用,毕竟与MVC架构相比,成本较高

本文主要介绍了关于ddd是什么意思(迁移过程中可能存在的疑问)的相关养殖或种植技术,生活常识栏目还介绍了该行业生产经营方式及经营管理,关注生活常识发展动向,注重系统性、科学性、实用性和先进性,内容全面新颖、重点突出、通俗易懂,全面给您讲解生活常识技术怎么管理的要点,是您生活常识致富的点金石。
以上文章来自互联网,不代表本人立场,如需删除,请注明该网址:http://seotea.com/article/1469725.html