前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DDD的基础设施到底在哪里

DDD的基础设施到底在哪里

作者头像
张逸
发布2023-03-23 18:09:37
9720
发布2023-03-23 18:09:37
举报
文章被收录于专栏:斑斓斑斓
Eric Evans对常见的三层架构做了优化,形成专属DDD的分层架构,如下图所示:

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

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

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

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

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

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

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

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

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

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

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

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

常见的外部资源包括:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最后,呼应标题。

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

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档