Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >领域驱动设计中的架构要素

领域驱动设计中的架构要素

作者头像
张逸
发布于 2018-10-10 02:47:06
发布于 2018-10-10 02:47:06
3.5K0
举报
文章被收录于专栏:斑斓斑斓

多数时候,领域驱动设计的分层架构并不能清晰表达各模块之间的依赖关系,以及这些模块在分层架构中所处的位置。因为我倾向于将Uncle Bob的Clean Architecture与DDD的分层架构整合起来,如下图所示:

在这个架构图中,基础设施层处于最外部,然后是应用层,最核心的是领域层。基础设施中的模块,我都称之为gateway。根据依赖方向,如果是被调用的方向,即由外至内的调用方向,就是北向,称之为北向网关。如果当前限界上下文是通过该网关调用外部资源或者别的限界上下文,即由内至外的调用方向,则是南向网关。例如图中的OrderController,会被别人调用,因而属于北向网关。注意,倘若OrderController通过RESTful方式暴露API,即为REST服务,也就是基于资源的服务。我们不能将它与DDD的应用服务混为一谈。

南向网关要特殊一些,它是打通应用层或领域层与外部资源(数据库消息队列、第三方服务)的通道。根据整洁架构的设计原则,我们不能让内层依赖外层,以保证内层的纯粹性与稳定性。为了解除应用层或领域层与它的耦合,南向网关往往需要提供接口。这就说明,基础设施层的南向网关都是具体实现,内层对南向网关的调用则通过接口和依赖注入。至于它们的接口,就应该放在领域层或者应用层。例如,数据库的持久化属于南向网关,但它们的抽象Repository就属于领域层。

通过上图,可以帮助我们明确各个模块和各层之间的职责。下图则基于这样的内外层架构清晰地表达了限界上下文(Bounded Context,以下简称BC)之间的协作关系,即DDD中的Context Map:

Context Map中有两个常用的模式OHS(开放主机服务)与ACL(防腐层)。显然,OHS就对应前面提到的北向网关,ACL就对应着南向网关。

为了遵循整洁架构原则,就需要为ACL提供一个抽象。例如订单要调用商家BC的服务,就需要在订单BC中定义一个被调用服务的接口,然后在ACL中,通过具体框架提供的跨进程调用方式,去真正发起对商家BC服务的调用。所以,我通常将代表ACL的模块命名为Client。通过Client可以防止上游BC发生变化时对下游BC产生直接影响。一旦变化发生,我们仅需要修改南向网关中的client实现。如下图所示:

这张图体现了有ACL和无ACL的区别。

下图体现了BC对领域概念的控制,它是控制领域概念一致性的边界。在DDD中,最好的方式是不去跨BC重用一个相同的领域概念:

假设我们的BC都是微服务,就是零共享架构,数据库是独立的。那么,各自BC关心的Product属性应该放在各自数据库中,它们的ID要保持一致。

现在基于这些认识来讨论两个问题:

  • 一个BC如何发起对另一个BC的调用
  • 调用时,是否会产生所谓的“领域模型”耦合

例如在订单BC中,如果在获得订单信息的同时,还需要获得订单中商品的信息以及该商品所属商家的信息,那么该谁发起对商家BC和商品BC的调用?

首先,我们在订单BC中定义自己的模型,该模型除了Order之外,还包含了商家与商品的信息,但这些信息是Read Model,是不需要在订单BC中持久化的。这就遵循了“BC是控制领域概念一致性的边界”这一原则。由于商家与商品在订单BC中并没有持久化的需求,因此当修改发生时,并不会因此而产生数据的不一致,更不会产生领域模型的耦合。这些领域模型都各自被定义在自己的BC中,没有重用。

其次,该谁来发起商家和商品BC的调用呢?通过第一张图与第二张图的讨论,我们需要在订单BC中定义商家BC和商品BC对应服务的接口(即前面提到的Client的接口),然后在领域层的相关对象(通常是领域服务),发起对这些接口的调用。框架会通过IoC框架注入Client实现,以满足对外部服务的调用。调用后,会在订单BC将返回的结果转换为自己BC的模型对象。如果需要组装最后的DTO,则可以在领域服务之上再包装一个应用服务,完成整个完整用例的逻辑。这样,就可以让Controller只调用应用服务,减少Controller对领域层的理解,从而遵循“最小知识”法则。

基于这样的设计思想,DDD的代码模型就可以定义为:

以下是对代码结构的说明:

  • application:对应了领域驱动设计的应用层,主要内容为该限界上下文中所有的应用服务。
  • interfaces:对gateways中除persistence之外的抽象,包括访问除数据库之外其他外部资源的抽象接口,以及对第三方服务或其他限界上下文服务的抽象接口。从分层架构的角度讲,interfaces应该属于应用层,但在实践时,往往会遭遇领域层需要访问这些抽象接口的情形,单独分离出interfaces,非常有必要。
  • domain:对应了领域驱动设计的领域层,但是我将repositories单独分了出来,目的是为了更好地体现它在基础设施层扮演的与外部资源打交道的网关语义。
  • repositories:代表了领域驱动设计中战术设计阶段的资源库,皆为抽象类型。如果该限界上下文的资源库并不复杂,可以将repositories合并到domain中。
  • gateways:对应了领域驱动设计的基础设施层,命名为gateways,则是为了更好地体现网关的语义,其下可以视外部资源的集成需求划分不同的包。其中,controllers相对特殊,它属于对客户端提供接口的北向网关,等同于上下文映射中“开放主机服务(OHS)”的概念。如果为了凸显它的重要性,可以将controllers提升到与application、domain、gateways同等层次。我之所以将其放在gateways之下,还是想体现它的网关本质。persistence对应了repositories抽象,至于其余网关,对应的则是application/interfaces下的抽象,包括消息队列以及与其他限界上下文交互的客户端,例如通过http通信的客户端。其中,client包下的实现类与interfaces下的对应接口组合起来,等同于上下文映射中“防腐层(ACL)”的概念。

归根结底,在运用DDD进行架构设计,并通过BC映射到微服务设计时,要遵循两方面的设计原则。

一个是普适性的架构与设计原则,例如整洁架构、分而治之思想、关注点分离、最小知识法则等。理解了这些原则,你就清楚该如何分配职责,如何解耦。

另一个是DDD的设计原则,搞清楚每个层的职责,层之间的关系,BC之间的关系,领域模型是什么?

在明白了这些设计原则的真谛时,当我们碰到DDD设计落地的问题时,不知道该如何处理时,都可以基于这些设计原则来做出符合当前场景的决策,而不要做个“寻章摘句老雕虫”,照搬书上的方法,只要书上未曾涉及到此问题,就无从应对了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 逸言 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
领域驱动设计对依赖的控制
我在《解构领域驱动设计》一书中分析了软件复杂度的成因,一曰规模,一曰结构,还有一个则是变化的影响。规模与结构存在一定的矛盾关系:解决规模复杂度的有效方法为“分而治之”,一旦系统被分解为多个更为细小的软件元素,结构复杂度就会增加。结构与变化之间存在互相影响的关系:如果结构控制不合理,变化带来的影响就会更强,使得系统更加复杂。
张逸
2023/03/23
4780
领域驱动设计对依赖的控制
《解构领域驱动设计》架构映射篇
本阶段,映射成为了获得架构的主要设计手段。价值需求中利益相关者、系统愿景和系统范围可映射为系统上下文,业务活动通过对业务相关性的归类与归纳可映射为限界上下文,二者又是构成系统架构的重要层次,前者勾勒出解空间的控制边界,后者勾勒出领域模型的知识边界,组成了一个稳定而又具有演进能力的领域驱动架构。
张逸
2023/03/23
4910
《解构领域驱动设计》架构映射篇
浅析领域驱动设计
DDD(Domain-driven design,模型驱动设计)是一种软件设计的指导思想,而非固定的一套公式化开发模板(这样就会导致网络上出现各种基于自己或业务上的理解而产出的DDD落地的实现,会让很想学习的开发者迷茫)。在项目的全生命周期内,所有岗位的人员都基于对业务的相同的理解来展开工作。所有人员站在用户的角度、业务的角度区思考问题,而不是从一开始就站在技术的角度去思考。
JusterZhu
2023/01/10
7660
浅析领域驱动设计
DDD在大众点评交易系统演进中的应用
本文主要涉及境外出行、商场团购和内容商业化等三类交易业务场景。在大众点评App里,在境外城市站有美食、购物、商场、景点、门票、当地玩乐等频道入口,可以购买境外出行交易产品,在境内的逛街/商场频道可以找到商场团购优惠以及商场团购代金券。
美团技术团队
2024/05/15
1990
DDD在大众点评交易系统演进中的应用
驱动领域DDD的微服务设计和开发实战
你是否还在为微服务应该拆多小而争论不休?到底如何才能设计出收放自如的微服务?怎样才能保证业务领域模型与代码模型的一致性?或许本文能帮你找到答案。 本文是基于 DDD 的微服务设计和开发实战篇,通过借鉴领域驱动设计思想,指导微服务项目团队进行设计和开发(理论篇详见《当中台遇上 DDD,我们该如何设计微服务?》)。本文包括三部分内容:第一部分讲述领域驱动设计基本知识,包括:分层架构、服务视图、数据视图和领域事件发布和订阅等;第二部分讲述微服务设计方法、过程、模板、代码目录、设计原则等内容;最后部分以一个项目为例讲述基于 DDD 的微服务设计过程。
星哥玩云
2022/07/29
7291
驱动领域DDD的微服务设计和开发实战
领域驱动设计(DDD)实践之路(一)
领域驱动设计(Domain Driven Design,DDD)其实并非新理论,大家可以看看 Eric Evans 编著的《领域驱动设计》原稿首版是2003年,距今已十余年时间。与现在的分布式、微服务相比,绝对是即将步入中年的“老家伙”了。
2020labs小助手
2020/02/24
1.4K0
菱形对称架构的表达力
在14年读《实现领域驱动设计》接触到六边形架构,感觉很受启发,每个限界上下文就对应一个六边形架构:
张逸
2023/03/23
7260
菱形对称架构的表达力
DDD实战之五:战略设计之上下文映射和系统分层架构
关于“限界上下文识别”和“限界上下文关系映射”,我认为这是 DDD 战略设计中最重要的部分,甚至可以说:这两个工作将决定了微服务切分是否有效的关键因素!
张逸
2023/03/23
1.6K0
DDD实战之五:战略设计之上下文映射和系统分层架构
领域驱动设计
本文对《领域驱动设计-软件复杂性应对之道》一书进行高度凝练,梳理了领域驱动设计的架构图、基本要素和重要概念。从细节入手,以小见大,你想知道的定义,这里都有。
kaiwest
2025/01/16
510
万字长文助你上手软件领域驱动设计 DDD
作者:faryrong,腾讯 CSIG 后台开发工程师 最近看了一本书《解构-领域驱动设计》,书中提出了领域驱动设计统一过程(DDDRUP),它指明了实践 DDD 的具体步骤,并很好地串联了各种概念、模式和思想。因此,我对书本内容做了梳理、简化,融入自己的理解,并结合之前阅读的书籍以及实践经验,最终形成这篇文章。希望可以帮助大伙理顺 DDD 的各种概念、模式和思想,降低上手 DDD 的门槛。 1.背景 领域驱动设计(DDD)由 Eric Evans 提出,并一经《领域驱动设计:软件核心复杂性应对之道》的发布
腾讯技术工程官方号
2022/03/29
2.1K0
阐释限界上下文
有人阅读我的文章,并指出文章错误,作为作者的我,应该表示真诚的感谢。文章写来没人读,不就是抛媚眼给瞎子看吗?有人指出错误,不仅能帮我勘误,还能增加知识,岂非一举两得。
张逸
2023/03/23
5910
阐释限界上下文
领域驱动设计实战
采用领域驱动设计方法进行问题空间分析及解空间设计。划分顾客、商家、骑手、订单、通知五个限界上下文,每个上下文成为一个微服务。服务内部采用分层架构。服务之间以开放主机服务及事件驱动架构。数据库逻辑隔离,通过事件机制保证最终一致性。
AlphaHinex
2024/09/25
1190
领域驱动设计实战
人人都在跟风学微服务,却不知道DDD领域驱动设计?
最先介绍领域驱动设计(domain-driven design)的是在程序员 Eric Evans 2004年出版的《领域驱动设计:复杂软件核心复杂应对之道》书籍中,领域驱动设计是领域概念的扩展和应用,并且将它应用在软件开发中。它的目标是将软件相关部分连接到不断发展的模型中,以此更容易创建复杂的应用。
Lvshen
2022/05/05
4290
人人都在跟风学微服务,却不知道DDD领域驱动设计?
领域驱动设计 (DDD) 总结
DDD (Domain-Driven Design),即领域驱动设计是思考问题的方法论,用于对实际问题建模,它以一种领域专家、设计人员、开发人员都能理解的通用语言作为相互交流的工具,然后将这些概念设计成一个领域模型。由领域模型驱动软件设计,用代码来实现该领域模型。所以,DDD 的核心是建立正确的领域模型。
剑影啸清寒
2020/07/15
3.1K0
领域驱动设计 (DDD) 总结
领域驱动设计——术语篇
随着微服务架构的普及,领域驱动设计(DDD)又重回软件设计战场。虽然团队内不少项目已经开始尝试,使用DDD指导项目的设计与开发,但还是有不少同学对DDD缺乏基础了解。因此,本文结合书本的定义及个人理解,对DDD中关键概念进行梳理,避免沟通时的歧义。毕竟DDD提倡使用通用语言,业务层面应该使用通用语言,技术层面也应该统一术语。
liliane
2022/07/27
8400
领域驱动设计实践:支付系统建模
点击上方蓝色字体,选择“设为星标” 回复”学习资料“获取学习宝典 文章来源:https://www.jdon.com/59597 目录 简介 什么是DDD 如何在实践中应用DDD 问题空间 解决方案空间 从领域模型到微服务 结论 在Airwallex,领域驱动设计(DDD)方法被用来指导如何对复杂的业务问题和系统设计进行建模。 在这篇博客中,我们试图全面介绍用DDD模式对支付系统进行建模的做法。 | 简介 支付系统是一个相当复杂和多变的系统,从订单、欺诈、通知、与各种支付方式的整合到资金清算和结
猿天地
2022/04/22
9830
领域驱动设计实践:支付系统建模
领域驱动设计(DDD)架构演进和DDD的几种典型架构介绍(图文详解)
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/03/24
8660
领域驱动设计对软件复杂度的应对
不管是因为规模与结构制造的理解力障碍,还是因为变化带来的预测能力问题,最终的决定因素还是因为需求。Eric Evans认为“很多应用程序最主要的复杂性并不在技术上,而是来自领域本身、用户的活动或业务”。因而,领域驱动设计关注的焦点在于领域和领域逻辑,因为软件系统的本质其实是给客户(用户)提供具有业务价值的领域功能。
张逸
2019/03/07
1K0
领域驱动设计对软件复杂度的应对
领域驱动设计之我见
2004年,Eric Evans 发表了《Domain-Driven Design –Tackling Complexity in the Heart of Software 》(领域驱动设计)这本书,简称Evans DDD,书里对领域驱动做了开创性的理论阐述。它为我们提供了设计软件的一个全新视角,同时也给开发者留下了一大难题:如何将领域驱动设计付诸实践?
saintyyu
2021/11/22
4920
领域驱动设计之我见
领域驱动设计统一过程交付物
我还在书中的附录D给出了领域驱动设计统一过程的交付物。不过,随着我在多个项目中实践领域驱动设计统一过程,我发现定义在交付物的一些关键元素需要更好的表现方式,也需要形成一个统一的标准。为了帮助各位《解构领域驱动设计》的读者在项目中更好地运用领域驱动设计统一过程,并输出高质量的统一而标准的交付物,特别作此文以补充。
张逸
2023/03/23
5740
领域驱动设计统一过程交付物
相关推荐
领域驱动设计对依赖的控制
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文