在评论DDD分层架构的形式之前,咱们先一同回忆一下DDD和分层架构的相关常识。

DDD作为一种软件开发办法,它能够协助咱们规划高质量的软件模型。在正确完结的情况下,咱们经过DDD完结的规划恰恰便是软件的作业方法。

UL是团队同享的言语,是DDD中最具威力的特性之一。不论你在团队中的人物怎么,只需你是团队的一员,你都将运用UL。因为UL的重要性,所以需求让每个概念在各自的上下文中是明晰无歧义的,所以DDD在战略规划上提出了形式BC。UL和BC一同构成了DDD的两大支柱,而且它们是相得益彰的,即UL都有其确认的上下文意义,而BC中的每个概念都有仅有的意义。

一个业务范畴区分红若干个BC,它们之间经过Context Map进行集成。BC是一个显式的鸿沟,范畴模型便存在于这个鸿沟之内。范畴模型是关于某个特定业务范畴的软件模型。一般,范畴模型经过方针模型来完结,这些方针一同包括了数据和行为,而且表达了精确的业务意义。

从广义上来讲,范畴便是一个组织所做的作业以及其间所包括的全部,表明整个业务体系。因为“范畴模型”包括了“范畴”这个词,咱们或许会以为应该为整个业务体系创立一个单一的、内聚的和全功用式的模型。可是,这并不是咱们运用DDD的方针。正好相反,范畴模型存在于BC内。

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

分层架构的一个重要准则是每层只能与坐落其下方的层发作耦合。分层架构能够简略分为两种,即严厉分层架构和松懈分层架构。在严厉分层架构中,某层只能与坐落其直接下方的层发作耦合,而在松懈分层架构中,则答应某层与它的恣意下方层发作耦合。

分层架构的长处是清楚明了的。首要,因为层间松懈的耦合联系,使得咱们能够专心于本层的规划,而不用关怀其他层的规划,也不用忧虑自己的规划会影响其它层,对进步软件质量大有裨益。其次,分层架构使得程序结构明晰,晋级和保护都变得十分简单,更改某层的具体完结代码,只需本层的接口坚持安稳,其他层能够不用修正。即便本层的接口发作变化,也只影响相邻的上层,修正作业量小且过错能够操控,不会带来意外的危险。

要坚持程序分层架构的长处,就必须坚持层间的松懈耦合联系。规划程序时,应先区分出或许的层次,以及此层次供给的接口和需求的接口。规划某层时,应尽量坚持层间的阻隔,仅运用基层供给的接口。

关于分层架构的长处,Martin Fowler在《Patterns of Enterprise Application Architecture》一书中给出了答案:

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

在每个BC中为了凸显范畴模型,DDD中提出了分层架构形式。最近几年,笔者在实践DDD的过程中,也常常运用分层架构形式,本文首要共享DDD分层架构中比较经典的三种形式。

Eric Evans在《范畴驱动规划-软件中心杂乱性应对之道》这本书中提出了传统的四层架构形式,如下图所示:

传统的四层架构都是限定型松懈分层架构,即Infrastructure层的恣意上层都能够拜访该层,而其它层恪守严厉分层架构。

笔者在四层架构形式的实践中,关于分层的本地化界说首要为:

阐明:严厉意义上来说,User Interface指的是用户界面,Restful音讯和配置文件解析等处理应该放在Application层,User Interface层没有的话就空缺。但User Interface也能够了解为用户接口,所以将Restful音讯和配置文件解析等处理放在User Interface层也行。

James O. Coplien和Trygve Reenskaug在2009年宣布了一篇论文《DCI架构:面向方针编程的新设想》,标志着DCI架构形式的诞生。风趣的是James O. Coplien也是MVC架构形式的发明者,这个大叔一辈子就干了两件事,即年轻时发明了MVC和年迈时发明了DCI,其他时刻都在考虑,让我辈望尘莫及。

面向方针编程的原意是将程序员与用户的视角共同于计算机代码之中:对进步可用性和下降程序的了解难度来说,都是一种赏赐。可是虽然方针很好地反映了结构,但在反映体系的动作方面却失利了,DCI的设想是期望反映出最终用户的认知模型中的人物以及人物之间的交互。

传统上,面向方针编程言语拿不出办法去捕捉方针之间的协作,反映不了协作中来往的算法。就像方针的实例反映出范畴结构相同,方针的协作与交互同样是有结构的。协作与交互也是最终用户心智模型的组成部分,但你在代码中找不到一个内聚的表现形式去代表它们。在本质上,人物表现的是一般化的、笼统的算法。人物没有血肉,并不能做实践的作业,归根到底作业仍是落在方针的头上,而方针自身还担负着表现范畴模型的责任。

人们心目中对“方针”这个共同的全体却有两种不同的模型,即“体系是什么”和“体系做什么”,这便是DCI要处理的根本问题。用户认知一个个方针和它们所代表的范畴,而每个方针还必须依照用户心目中的交互模型去完结一些行为,经过它在用例中所扮演的人物与其他方针联合在一同。正因为最终用户能把两种视角合为一体,类的方针除了支撑所属类的成员函数,还能够实行所扮演人物的成员函数,就好像那些函数归于方针自身相同。换句话说,咱们期望把人物的逻辑注入到方针,让这些逻辑成为方针的一部分,而其位置却一点点不弱于方针初始化时从类所得到的办法。咱们在编译时就为方针组织好了扮演人物时或许需求的一切逻辑。假如咱们再聪明一点,在运转时才知道了被分配的人物,然后注入刚好要用到的逻辑,也是能够做到的。

算法及人物-方针映射由Context具有。Context“知道”在当时用例中应该找哪个方针去充任实践的艺人,然后担任把方针“cast”成场景中的相应人物。在典型的完结里,每个用例都有其对应的一个Context 方针,而用例涉及到的每个人物在对应的Context 里也都有一个标识符。Context 要做的仅仅将人物标识符与正确的方针绑定到一同。然后咱们只需触发Context里的“开场”人物,代码就会运转下去。

所以咱们有了完好的DCI架构:

DCI现在广泛被看作是对DDD的一种开展和弥补,用在依据面向方针的范畴建模上。显式的对role进行建模,处理了面向方针建模中的充血模型和贫血模型之争。DCI经过显式的用role对行为进行建模,一同让role在context中能够和对应的范畴方针进行绑定,然后既处理了数据鸿沟和行为鸿沟不共同的问题,也处理了范畴方针中数据和行为高内聚低耦合的问题。

面向方针建模面对的一个扎手问题是数据鸿沟和行为鸿沟往往不共同。遵从模块化的思维,咱们经过类将行为和其严密耦合的数据封装在一同。可是在杂乱的业务场景下,行为往往跨过多个范畴方针,这样的行为假如放在某一个方针中必然会导致其他方针需求向该方针暴漏其内部状况。所以面向方针开展的后来,范畴建模呈现两种派系之争,一种倾向于将跨过多个范畴方针的行为建模在范畴服务中。假如这种做法运用过度,则会导致范畴方针变成只供给一堆get办法的哑方针,这种建模成果被称之为贫血模型。而另一派则坚决的以为办法应该归于范畴方针,所以一切的业务行为依然被放在范畴方针中,这样导致范畴方针跟着支撑的业务场景变多而变成天主类,而且类内部办法的笼统层次很难共同。别的因为行为鸿沟很难恰当,导致方针之间数据拜访联系也比较杂乱,这种建模成果被称之为充血模型。

关于多人物方针,举个日子中的比方:

人有多重人物,不同的人物实行的责任不同:

这里人聚合了多个人物,人在某种场景下,只能扮演特定的人物:

引进DCI后,DDD四层架构形式中的Domain层变薄了,曾经Domain层对应DCI中的三层,而现在:


因而,DDD分层架构形式就变成了五层,如下图所示:

笔者在实践中,将这五层的本地化界说为:

DDD五层架构形式评论完了吗?故事还没有完毕……

笔者参加的许多DDD落地实践,都是面向操控面或办理面且音讯交互比较多的体系。这类体系的一次业务,包括一组同步音讯或异步音讯构成的序列,假如都放在Context层,会导致该层的代码比较杂乱,所以咱们考虑:

因而,在面向操控面或办理面且音讯交互比较多的体系中,DDD分层架构形式就变成了六层,如下图所示:

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

业务层的中心是业务模型,业务模型的结构代码一般放在基础设施层。关于业务模型,笔者曾经共享过一篇文章——《 Golang业务模型 》,感兴趣的同学能够看看。

综上所述,DDD六层架构能够看做是DDD五层架构在特定范畴的变体,咱们统称为DDD五层架构,而DDD五层架构与传统的四层架构相似,都是限定型松懈分层架构。

有一种办法能够改善分层架构,即依靠倒置准则,它经过改动不同层之间的依靠联系抵达改善意图。

依靠倒置准则由Robert C. Martin提出,正式界说为:

依据该界说,DDD分层架构中的低层组件应该依靠于高层组件供给的接口,即不管高层仍是低层都依靠于笼统,整个分层架构好像被推平了。假如咱们把分层架构推平,再向其间参加一些对称性,就会呈现一种具有对称性特征的架构风格,即六边形架构。六边形架构是Alistair Cockburn在2005年提出的,在这种架构中,不同的客户经过“相等”的方法与体系交互。需求新的客户吗?不是问题。只需求增加一个新的适配器将客户输入转化成能被体系API所了解的参数就行。一同,关于每种特定的输出,都有一个新建的适配器担任完结相应的转化功用。

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

六边形每条不同的边代表了不同类型的端口,端口要么处理输入,要么处理输出。关于每种外界类型,都有一个适配器与之对应,外界经过应用层API与内部进行交互。上图中有3个客户恳求均抵达相同的输入端口,另一个客户恳求运用了适配器D。假定前3个恳求运用了HTTP协议,然后一个恳求运用了AMQP协议。端口并没有明晰的界说,它是一个十分灵敏的概念。不管选用哪种方法对端口进行区分,当客户恳求抵达时,都应该有相应的适配器对输入进行转化,然后端口将调用应用程序的某个操作或许向应用程序发送一个事情,操控权由此交给内部区域。

应用程序经过公共API接纳客户恳求,运用范畴模型来处理恳求。咱们能够将DDD战术规划的建模元素Repository的完结看作是耐久化适配器,该适配器用于拜访从前存储的聚合实例或许保存新的聚合实例。正如图中的适配器E、F和G所展现的,咱们能够经过不同的方法完结资源库,比方联系型数据库、依据文档的存储、分布式缓存或内存存储等。假如应用程序向外界发送范畴事情音讯,咱们将运用适配器H进行处理。该适配器处理音讯输出,而上面说到的处理AMQP音讯的适配器则是处理音讯输入的,因而应该运用不同的端口。

咱们在实践的项目开发中,不同层的组件能够一同开发。当一个组件的功用明晰后,就能够当即发动开发。因为该组件的用户有多个,而且这些用户的侧重点不同,所以需求供给多个不同的接口。一同,这些用户的知道也是不断深入的,或许会屡次重构相关的接口。所以,组件的多个用户常常会找组件的开发者评论这些问题,无形中下降了组件的开发功率。

咱们换一种方法,组件的开发者在明晰了组件的功用后就专心于功用的开发,保证功用安稳和高效。组件的用户自己界说组件的接口,然后依据接口写测验,并不断演进接口。在跨层集成测验时,由组件开发者或用户再开发一个适配器就能够了。

虽然六边形架构形式现已很好,可是没有最好只要更好,演化没有止境。在六边形架构形式提出后的这些年,又顺次衍生出三种六边形架构形式的变体,感兴趣的读者能够自行学习:

本文先和读者一同回忆了DDD和分层架构的相关常识,然后将DDD分层架构中常用的三种形式结合实践经验别离进行具体论述,使得读者深刻了解DDD分层架构形式,以便在微服务的开发实践中依据具体情况挑选最合适的DDD分层架构形式,然后交给结构明晰且易保护的软件产品。

原文链接: https://www.jianshu.com/p/a775836c7e25 ,作者:张晓龙

Online
TEL