还在搞三层架构?DDD 分层架构了解下!

上一篇:深夜看了张一鸣的微博,让我越想越后怕

引言

在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识。

DDD

DDD(Domain DrivenDesign,领域驱动设计)作为一种软件开发方法,它可以帮助我们设计高质量的软件模型。在正确实现的情况下,我们通过DDD完成的设计恰恰就是软件的工作方式。

UL(Ubiquitous Language,通用语言)是团队共享的语言,是DDD中最具威力的特性之一。不管你在团队中的角色如何,只要你是团队的一员,你都将使用UL。由于UL的重要性,所以需要让每个概念在各自的上下文中是清晰无歧义的,于是DDD在战略设计上提出了模式BC(BoundedContext,限界上下文)。UL和BC同时构成了DDD的两大支柱,并且它们是相辅相成的,即UL都有其确定的上下文含义,而BC中的每个概念都有唯一的含义。

一个业务领域划分成若干个BC,它们之间通过Context Map进行集成。BC是一个显式的边界,领域模型便存在于这个边界之内。领域模型是关于某个特定业务领域的软件模型。通常,领域模型通过对象模型来实现,这些对象同时包含了数据和行为,并且表达了准确的业务含义。

从广义上来讲,领域即是一个组织所做的事情以及其中所包含的一切,表示整个业务系统。由于“领域模型”包含了“领域”这个词,我们可能会认为应该为整个业务系统创建一个单一的、内聚的和全功能式的模型。然而,这并不是我们使用DDD的目标。正好相反,领域模型存在于BC内。

在微服务架构实践中,人们大量地使用了DDD中的概念和技术:

  1. 微服务中应该首先建立UL,然后再讨论领域模型。

  2. 一个微服务最大不要超过一个BC,否则微服务内会存在有歧义的领域概念。

  3. 一个微服务最小不要小于一个聚合,否则会引入分布式事务的复杂度。

  4. 微服务的划分过程类似于BC的划分过程,每个微服务都有一个领域模型。

  5. 微服务间的集成可以通过Context Map来完成,比如ACL(Anticorruption Layer,防腐层)。

  6. 微服务间最好采用Domain Event(领域事件)来进行交互,使得微服务可以保持松耦合。

分层架构

分层架构的一个重要原则是每层只能与位于其下方的层发生耦合。分层架构可以简单分为两种,即严格分层架构和松散分层架构。在 严格分层架构中,某层只能与位于其直接下方的层发生耦合,而在 松散分层架构 中,则允许某层与它的任意下方层发生耦合。

分层架构的好处是显而易见的。首先,由于层间松散的耦合关系,使得我们可以专注于本层的设计,而不必关心其他层的设计,也不必担心自己的设计会影响其它层,对提高软件质量大有裨益。其次,分层架构使得程序结构清晰,升级和维护都变得十分容易,更改某层的具体实现代码,只要本层的接口保持稳定,其他层可以不必修改。即使本层的接口发生变化,也只影响相邻的上层,修改工作量小且错误可以控制,不会带来意外的风险。

要保持程序分层架构的优点,就必须坚持层间的松散耦合关系。设计程序时,应先划分出可能的层次,以及此层次提供的接口和需要的接口。设计某层时,应尽量保持层间的隔离,仅使用下层提供的接口。关于分层架构的优点,Martin Fowler在《Patterns of Enterprise Application Architecture》一书中给出了答案:

  1. 开发人员可以只关注整个结构中的某一层。

  2. 可以很容易的用新的实现来替换原有层次的实现。

  3. 可以降低层与层之间的依赖。

  4. 有利于标准化。

  5. 利于各层逻辑的复用。

“金无足赤,人无完人”,分层架构也不可避免具有一些缺陷:

  1. 降低了系统的性能。这是显然的,因为增加了中间层,不过可以通过缓存机制来改善。

  2. 可能会导致级联的修改。这种修改尤其体现在自上而下的方向,不过可以通过依赖倒置来改善。

模式一:四层架构

Eric Evans在《领域驱动设计-软件核心复杂性应对之道》这本书中提出了传统的四层架构模式,如下图所示:

2、DCI中的Context层从Domain层上移变成Context层。因此,DDD分层架构模式就变成了五层,如下图所示:

笔者在实践中,将这六层的本地化定义为:

  1. User Interface是用户接口层,主要用于处理用户发送的Restful请求和解析用户输入的配置文件等,并将信息传递给Scheduler层的接口。

  2. Scheduler是调度层,负责多进程管理及调度、多线程管理及调度、多协程调度和维护业务实例的状态模型。当调度层收到用户接口层的请求后,委托Transaction层与本次操作相关的事务进行处理。

  3. Transaction是事务层,对应一个业务流程,比如UE Attach,将多个同步消息或异步消息的处理序列组合成一个事务,而且在大多场景下,都有选择结构。万一事务执行失败,则立即进行回滚。当事务层收到调度层的请求后,委托Context层的Action进行处理,常常还伴随使用Context层的Specification(谓词)进行Action的选择。

  4. Context是环境层,以Action为单位,处理一条同步消息或异步消息,将Domain层的领域对象cast成合适的role,让role交互起来完成业务逻辑。环境层通常也包括Specification的实现,即通过Domain层的知识去完成一个条件判断。

  5. Domain层是领域层,定义领域模型,不仅包括领域对象及其之间关系的建模,还包括对象的角色role的显式建模。

  6. Infrastructure层是基础实施层,为其他层提供通用的技术能力:业务平台,编程框架,持久化机制,消息机制,第三方库的封装,通用算法,等等。

事务层的核心是事务模型,事务模型的框架代码一般放在基础设施层。关于事务模型,笔者以前分享过一篇文章—  《Golang事务模型》 ,感兴趣的同学可以看看。

综上所述,DDD六层架构可以看做是DDD五层架构在特定领域的变体,我们统称为DDD五层架构,而DDD五层架构与传统的四层架构类似,都是限定型松散分层架构 。 

模式三:六边形架构

有一种方法可以改进分层架构,即依赖倒置原则(Dependency Inversion Principle,DIP),它通过改变不同层之间的依赖关系达到改进目的。

依赖倒置原则由Robert C. Martin提出,正式定义为:高层模块不应该依赖于底层模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。

根据该定义,DDD分层架构中的低层组件应该依赖于高层组件提供的接口,即无论高层还是低层都依赖于抽象,整个分层架构好像被推平了。如果我们把分层架构推平,再向其中加入一些对称性,就会出现一种具有对称性特征的架构风格,即六边形架构。六边形架构是AlistairCockburn在2005年提出的,在这种架构中,不同的客户通过“平等”的方式与系统交互。需要新的客户吗是问题。只需要添加一个新的适配器将客户输入转化成能被系统API所理解的参数就行。同时,对于每种特定的输出,都有一个新建的适配器负责完成相应的转化功能。

六边形架构也称为端口与适配器,如下图所示:

一个人学习、工作很迷茫br>

点击「阅读原文」加入我们的小圈子!

还在搞三层架构?DDD 分层架构了解下!

文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览92167 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年3月13日
下一篇 2021年3月13日

相关推荐