DDD架构为什么应该首选六边形架构?

ddd,架构,为什么,应该,首选,六边形 · 浏览次数 : 429

小编点评

**六边形架构分层架构的优势:** * 降低了依赖关系,使代码更易维护。 * 提高了代码可测试性。 * 增强了代码可移植性。 * 减少了代码维护成本。 * 提高了代码可扩展性。 **六边形架构的缺点:** * 要求开发人员了解多种技术。 * 可能会导致代码更难以理解。 * 可能会导致性能下降。 **依赖倒置原则的优势:** * 降低了依赖关系,使代码更易维护。 * 提高了代码可测试性。 * 增强了代码可移植性。 * 减少了代码维护成本。 **依赖倒置原则的缺点:** * 可能会导致一些复杂性。 * 可能会导致代码难以理解。 * 可能会导致性能下降。 **六边形架构和依赖倒置原则的比较:** | 特征 | 六边形架构 | 依赖倒置原则 | |---|---|---| | 依赖关系 | 低 | 高 | | 代码可维护性 | 高 | 低 | | 代码可测试性 | 高 | 低 | | 代码可移植性 | 高 | 低 | | 代码维护成本 | 低 | 高 | | 代码可扩展性 | 高 | 低 |

正文

一、传统分层架构

分层架构的一个重要原则是:每层只能与位于其下方的层发生耦合。

分层架构分两种:一种是严格分层架构,规定某层只能与直接位于其下方的层发生耦合;另一种是松散分层架构,允许任意上方层与任意下方层发生耦合。

下图是一个典型的DDD传统分层架构。

以上分层架构中各层都有自己的职责:

用户接口层负责处理用户请求和用户显示;

应用层实现不同业务场景下的用例或业务流程。其中应用服务通常接收来自用户接口层的请求,然后通过资源库获取聚合实例,最后执行相应的命令操作,如下示例:

// 应用层的用例 
public void cancelOrder(Long orderId) { 
    Order order = orderRepository.findById(orderId); 
    // 领域层的业务逻辑 
    order.cancel() 
    orderRepository.save(order); 
}

领域层实现系统的核心业务逻辑,主要包含基于DDD业务建模产生的领域模型,这里的业务逻辑不同于应用层中的业务流程,如上代码示例;

基础设施层为其它各层提供通用的技术和基础服务,比如数据持久化功能。

二、传统分层架构的问题

DDD中资源库(Repository)用来获取或持久化聚合,每个聚合都拥有一个对应的资源库。由此可见资源库应该和聚合位于同一层,资源库接口定义应该位于领域层,而资源库接口实现需要依赖基础设施层的持久化机制,此时资源库接口实现放在哪一层对传统分层架构来说是个问题。

如果把资源库接口实现放在基础设施层,那么基础设施层就会向上依赖领域层,这样就违反了分层架构的原则:每层只能与位于其下方的层发生耦合。

或者可以放在领域层,但是这样会使领域层依赖数据持久化的实现细节,导致领域层不再是一个稳定层。

也可以放在应用层,不过和放在领域层会有同样的问题。

那有没有更好的方式呢?

有,采用依赖倒置,打破分层架构原则。

三、依赖倒置原则

依赖倒置(或依赖反转)原则(Dependency inversion principle,DIP),由Bob大叔提出,其定义如下:

高层模块不应该依赖于低层模块,两者都应该依赖于抽象。 抽象不应该依赖于细节,细节应该依赖于抽象。

我们把资源库接口实现放在基础设施层,让基础设施层向上依赖领域层。虽然这样违背了分层架构原则,但是却符合依赖倒置原则:领域层(高层模块)不依赖基础设施层(低层模块),两者都依赖于资源库接口(抽象)。采用了依赖倒置后,同时调整下基础设施层位置,此时分层架构如下图:

四、六边形架构

分层架构采用依赖倒置原则后,实际上已经不存在分层的概念了。无论是高层还是低层,都只依赖于抽象,好像把整个分层架构给推平了一样。推平后的分层架构如下图:

给推平的分层架构补上左侧对称的另一半,其结果就类似六边形架构,如下图是六边形架构。

六边形架构也叫端口和适配器。在这种架构中,针对系统输入输出的不同交互方式,比如http、rpc、mq、数据持久化等,都有与之对应的适配器,适配器又通过应用层API与内部进行交互。

六边形架构让应用程序能够以一致的方式被用户、程序、自动化测试、批处理脚本所驱动,而且能够让应用程序的边界更加清晰。有关六边形架构的详细信息可以查看 六边形架构原文翻译

五、为什么不选择整洁架构?

整洁架构是Bob大叔在其《架构整洁之道》一书中,对六边形架构和其他类似架构做了总结和抽象之后,提出的一种架构设计理念。

书中总结出,六边形架构和其他类似架构设计出来的系统,都具有相同的特点:

独立于框架:这些系统的架构并不依赖某个功能丰富的框架之中的某个函数。框架可以被当成工具来使用,但不需要让系统来适应框架。 可被测试:这些系统的业务逻辑可以脱离UI、数据库、Web服务以及其他的外部元素来进行测试。 独立于UI:这些系统的UI变更起来很容易,不需要修改其他的系统部分。 独立于数据库:我们可以轻易将这些系统使用的Oracle、SQL Server替换成Mongo、BigTable、CouchDB之类的数据库。因 为业务逻辑与数据库之间已经完成了解耦。 独立于任何外部机构:这些系统的业务逻辑并不需要知道任何其他外部接口的存在。

综合以上所有架构的设计理念,Bob大叔提出了整洁架构设计理念,如下图。

以上图中同心圆分别代表了软件系统的不同层次,通常越靠近中心,其所在的软件层次就越高。

整洁架构规定了层之间的依赖关系规则:内层(高层)不依赖外层(低层),六边形架构层之间的依赖关系也遵从此规则。

至此可以认为整洁架构是一种架构设计的指导思想,六边形架构是整洁架构的一种具体的架构设计。

六、总结

采用依赖倒置原则后的分层架构和六边形架构,实际上都符合整洁架构设计理念。但是六边形架构中使用端口与适配器,让应用程序能够以一致的方式被用户、程序、自动化测试、批处理脚本所驱动,同时能够让应用程序边界更加清晰,从而能更好地防止领域层和应用层逻辑泄露到外层。

七、参考

1.《实现领域驱动设计》

2.《架构整洁之道》

作者:京东零售 加文雄

来源:京东云开发者社区

与DDD架构为什么应该首选六边形架构?相似的内容:

DDD架构为什么应该首选六边形架构?

采用依赖倒置原则后的分层架构和六边形架构,实际上都符合整洁架构设计理念。但是六边形架构中使用端口与适配器,让应用程序能够以一致的方式被用户、程序、自动化测试、批处理脚本所驱动,同时能够让应用程序边界更加清晰,从而能更好地防止领域层和应用层逻辑泄露到外层。

【实践篇】领域驱动设计:DDD工程参考架构

不同团队落地DDD所采取的应用架构风格可能不同,并没有统一的、标准的DDD工程架构。即使无法制定通用的、标准的工程应用架构,但为团队制定一个遵循领域驱动设计思想的参考架构依然有价值。

【实践篇】手把手教你落地DDD

本文通过对贫血三层架构进行精炼,推导出适合我们落地的应用架构,并且将之实现为Maven Archetype以应用到实际开发,然而应用架构只是落地DDD的一个知识点,要完整落地DDD还必须体系化地掌握限界上下文、上下文映射、充血模型、实体、值对象、领域服务、Factory、Repository等知识点。

快速理解DDD领域驱动设计架构思想-基础篇

本文与大家一起学习并介绍领域驱动设计(Domain Drive Design) 简称DDD,以及为什么我们需要领域驱动设计,它有哪些优缺点,尽量用一些通俗易懂文字来描述讲解领域驱动设计

DDD项目落地之充血模型实践

充血模型是DDD分层架构中实体设计的一种方案,可以使关注点聚焦于业务实现,可有效提升开发效率、提升可维护性

Golang 依赖注入设计哲学|12.6K 的依赖注入库 wire

本文从“术”层面,讲述“依赖注入”的实现,带你体会其对于整洁架构 & DDD 等设计思想的落地,起到的支撑作用。

火山引擎A/B测试平台的实验管理重构与DDD实践

本次分享的主题是火山引擎数智平台VeDI旗下的A/B测试平台 DataTester 实验管理架构升级与DDD实践。这里说明的一点是,代码的第一目标肯定是满足产品需求,能够满足产品需求的代码都是好代码。而本文中对代码的好坏的评价完全是从架构的视角,结合代码的可读性、可维护性与可扩展性去分析的。 在一个

认知篇:CQRS架构模式的本质

CQRS只是一种非常简单的模式(pattern),CQRS本身并不是一种架构风格,和最终一致性/消息/读写分离/事件溯源/DDD等没有必然的联系,它最大优势是给我们带来更多的架构属性选择

大营销抽奖系统,DDD开发要如何建模?

作者:小傅哥 博客:https://bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获! 大家好,我是技术UP主小傅哥。 ‍ 经过5.1假期的一顿框框输出,终于完成了《大营销项目》第二阶段的开发和上线,体验地址:https://gaga.plus 有了这个项目的落地,

产品代码都给你看了,可别再说不会DDD(七):实体与值对象

这是一个讲解DDD落地的文章系列,作者是《实现领域驱动设计》的译者滕云。本文章系列以一个真实的并已成功上线的软件项目——码如云(https://www.mryqr.com)为例,系统性地讲解DDD在落地实施过程中的各种典型实践,以及在面临实际业务场景时的诸多取舍。 本系列包含以下文章: DDD入门