DDD的基础设施到底在哪里

简介: DDD的基础设施到底在哪里

Eric Evans对常见的三层架构做了优化,形成专属DDD的分层架构,如下图所示:

image.png

Eric对基础设施层(Infrastructure Layer)的定义为:“为上面各层提供通用的技术能力:为应用层传递消息,为领域层提供持久化机制,为用户界面层绘制屏幕组件,等等。基础设施层还能够通过架构框架来支持4个层次间的交互模式。

从DDD的分层架构看,领域层对基础设施层产生了依赖,这违背了依赖倒置原则:上层模块不应该依赖于下层模块,而应该依赖于下层模块的抽象。所以,Vernon在《实现领域驱动设计》中,将上图所示的分层架构修改为下图的结构:

image.png

基础设施层挪到了最上面,领域层没有任何依赖,就能让领域层更加纯粹,不再收到外界变化的影响。然而,事与愿违,领域层依旧有必须依赖基础设施层的理由,例如,领域层的领域服务就必然需要访问数据库,这一功能属于基础设施层的职责。

该如何处理领域层与基础设施层的关系?Eric的解决方式是引入Repository模式。他选择将Repository的接口放到领域层,实现放到基础设施层。如此一来,领域服务对Repository接口的调用就属于同层之间的依赖,而实现则交给了依赖注入,由其在运行时将实现逻辑绑定到领域服务,如此就解除了领域层与基础设施层的耦合。

如果将Repository对领域对象的操作视为对对象集合的操作,将Repository放到领域层也就顺理成章了。可是对于一个业务系统而言,领域层不仅仅需要访问数据库,如果需要访问消息队列传递消息呢,需要访问文件呢,需要网络通信呢?难道要将所有访问外部资源的接口都归属到领域层吗?这明显不合理。

Eric提出分层架构的主要目的是为了分离领域层,实现业务和技术的正交。实现该目标的最佳途经莫过于分离基础设施层的接口与实现,如此也恰好满足依赖倒置原则。菱形对称架构的南向网关之所以分为端口和适配器,原因就在此。

image.png

逻辑上,端口和领域层彼此分离,但由于二者存在双向依赖,在物理上,需要它们部署在一起。而适配器和端口则可以分开,以满足接口与实现分离的设计要求。

按照Eric对基础设施层的定义,北向网关的远程服务也属于基础设施的一种。分层架构的应用层对应于北向网关的本地服务层。菱形对称模式彻底改变了DDD分层架构的定义,更接近整洁架构和六边形架构,属于内外分层的表现形式。

菱形对称架构也可体现为分层架构形式:

image.png

菱形对称架构是为DDD的限界上下文量身定做。由于限界上下文是业务能力的纵向切分,在其边界内,不仅包含领域层,也包含了网关层,甚至其逻辑边界还包含它要访问的数据库。若回到基础设施的语义,也就认为限界上下文包含基础设施层。

倘若基础设施只为当前限界上下文服务也就罢了,一旦有别的限界上下文也需要调用,又该如何处理?

在讨论此问题之前,有必要明确DDD的基础设施层究竟包含哪些内容。注意,DDD的基础设施并不等同于云计算IaaS层对应的基础设施,它是一种隐喻,代表了支撑领域逻辑的基础功能,同样由当前开发团队编码实现,通常用于封装对外部资源的访问。

常见的外部资源包括:

  • 数据库
  • 缓存
  • 设备
  • 外部接口
  • 消息队列

由于访问基础设施的调用者是领域层,因此,不要将操作外部资源的框架与其混为一谈。这一定义与Eric对基础设施层的定义略有不同,但我认为才是正解。

以订单上下文为例。南向网关访问数据库的基础设施可以是OrderRepository端口和适配器,但它显然不是Hibernate或MyBatis这样的ORM框架;访问Kafka的基础设施可以是OrderPlacedPublisher端口和适配器,而不是spring-kafka框架;至于对上游限界上下文的访问,更是如此,不必多说。

弄清楚二者的区别,就可以深刻理解到:一个限界上下文内部的基础设施,往往带有当前限界上下文的业务含义,是相对专有的,实际上,很少存在跨限界上下文复用的可能。

一种特殊场景是Context Map的防腐层模式,它在菱形对称架构中体现为Client端口,用于封装对上游限界上下文或伴生系统外部接口的访问。如果上游限界上下文的北向网关服务会被多个下游访问,又需要引入防腐层隔离上游的变化,就存在多个限界上下文防腐层实现的重复。

为避免重复,常见的做法是将该防腐层升级为一个专有的限界上下文。一个典型例子是支付限界上下文。在电商系统中,支付系统属于目标系统之外的伴生系统。支付订单、发起退款,缴纳会员费等多个业务场景都需要调用支付系统。如果分别为其实现防腐层,就会在订单上下文、售后上下文与会员上下文中,散落着重复的支付适配逻辑,解决办法就是专门为其定义一个支付上下文。

我曾提到过,对于一个规模相对较大的目标系统而言,架构要考虑两个层次:

  • 系统上下文
  • 限界上下文

目前,限界上下文的基础设施问题已经给予澄清,那么,在系统层次,又该如何考虑?

由于限界上下文是业务能力的纵向切分,一个自治的限界上下文,就必须包含它所需要的完整的内容,如果将每个限界上下文都看做是一个独立的子系统,在系统层次似乎就没有基础设施的必要了。

我正是这般认为的,但恐怕一些人并不怎么认为。之所以存在分歧,是因为我们对基础设施的定义并未达成一致。

譬如说,有人认为,用户管理、组织管理与权限认证属于整个系统的基础设施;我却认为它们应该属于映射到通用子领域的限界上下文,在系统架构中,位于分层架构的基础层:

image.png

又有人认为,诸如Spring Cloud、Hibernate、Seata、Dubbo之类的框架属于整个系统都需要的基础设施,故而需要定义专门的基础设施层。如前所述,我认为它们并非DDD分层架构的基础设施层。

这里牵涉到对架构视图的理解。无论是DDD分层架构,还是我提出的系统分层架构与菱形对称架构,都属于应用逻辑架构的一部分。系统需要使用的框架根本就不在应用架构的范围内。如果要在架构中体现它们,应该放到技术架构。若要了解架构视图的详细内容,可以参考阅读我的系列文章《全面探索架构师图

最后,呼应标题。

DDD分层架构的基础设施并非技术架构中的框架或平台,而是限界上下文领域层需要调用的端口或适配器,它们位于限界上下文内部的南向网关,又或者基于复用的必要,被抽离出来形成单独的限界上下文。为避免与云平台或其他基础架构提及的基础设施混淆,我建议慎用这一术语。若要使用,需先明确其真正的含义,了解它包含的实际内容。

END

相关文章
|
4月前
|
存储 设计模式 算法
DDD之于业务支撑的意义
DDD之于业务支撑的意义
102 0
|
11月前
|
消息中间件 JavaScript 小程序
领域驱动设计(DDD)的几种典型架构介绍
领域驱动设计(DDD)的几种典型架构介绍
|
11月前
|
架构师 安全
「技术架构」EA874:技术架构的原则和标准
「技术架构」EA874:技术架构的原则和标准
|
11月前
|
敏捷开发 架构师 领域建模
别吵,可落地的DDD!
别吵,可落地的DDD!
406 0
|
11月前
|
消息中间件 JavaScript 小程序
拥抱毒瘤 DDD!
拥抱毒瘤 DDD!
|
架构师 算法 测试技术
小团队也能做DDD
小团队也能做DDD
|
设计模式 前端开发 数据库
微服务架构谈(4) plus:DDD 分层架构如何推动架构演进
微服务架构谈(4) plus:DDD 分层架构如何推动架构演进
814 0
微服务架构谈(4) plus:DDD 分层架构如何推动架构演进
|
Java API 领域建模
领域驱动设计(DDD)-简单落地
一、序言     领域驱动设计是一种解决业务复杂性的设计思想,不是一种标准规则的解决方法。在本文中的实战示例可能会与常见的DDD规则方法不太一样,是简单、入门级别,新手可以快速实践版的DDD。如果不熟悉DDD设计思想可看下基础思想篇 二、设计阶段     领域建模设计阶段常见的方法有 四色建模法、EventSourcing等 推荐一篇博文正确理解领域建
11466 1
|
设计模式 JSON 缓存
|
自然语言处理 测试技术 领域建模
DDD的优势(3)
DDD的优势(3)
232 0
DDD的优势(3)

热门文章

最新文章

相关课程

更多