DDD 领域驱动设计学习(四)- 架构(分层/六边形/RESTful)

DDD方法中并没有指定使用特定的架构。领域中的BC被封装为高内聚的模块,这种特性让DDD对架构并没有太大侵入性。架构可以应用于领域内部的结构,也可以包围着领域模型,系统中可以采用多种风格的架构。

架构是指构成一个系统的主要元素及它们之间的主要关联,这些元素和关联能够反映该系统的本质特征。

选择架构应该了解架构的来源和所要解决的问题,从业务和问题出发,避免滥用架构。例如分布式应用的架构有REST、DO(分布式对象)和RPC,REST架构是Web风格的架构,而DO和RPC是面向企业应用的,技术和架构也不是一个概念,例如用了HTTP不一定就是Web架构。
以建筑为例,苏州园林是一种建筑风格,欧洲的哥特式教堂也是一钟建筑风格,在苏州园林中放个哥特式教堂就让让人感觉画风突兀。

分层架构

分层架构是一种历史悠久的架构,通过分层架构,可以将系统按不同职责组织成有序层次,由于这种划分往往比较容易界定,也算是最常见和最受欢迎的一种架构,有一个说法是:“如果你不知道要用什么架构,那就用它。
Fowler在《Patterns of Enterprise Application Architecture》中对分层的定义是:

当我们说一个系统是分层架构的时候,你可以把这个软件想象成一个有很多层的蛋糕的样子,其中每一层放在它的下一层上。较高层使用诸多较低层定义和提供的服务,但较低层并没有察觉较高层的存在。另外,每一层都会对其上层隐藏更低的层。

介绍分层的文章和例子都比较多,不再赘述,简要说下DDD中的分层模型。

在分层架构中,我们将领域模型和业务逻辑分离出来,并减少对基础设施、用户界面甚至应用层逻辑的依赖,因为它们不属于业务逻。将一个复杂的系统分为不同的层,每层都应该具有良好的内聚性,并且只依赖于比其自身更低的层。[Evans, Ref, P16]

一个DDD中的分层架构可以如下图所示,通过把领域层单独分离出来,负责表达业务概念,业务状态以及业务规则,形成对领域知识的集中并形成业务软件的核心。


DDD分层架构

不过从分层架构图中可以发现,将基础设施层放入底层是存在缺点的,领域层依赖于基础设施层,这对领域层的内聚性产生影响。一个解决方案就是依赖倒置。

依赖倒置

依赖倒置的原则(DIP)由Robert C. Martin提出,核心的定义是:

高层模块不应该依赖于底层模块,两者都应该依赖于抽象
抽象不应该依赖于实现细节,实现细节应该依赖于接口

按照DIP的原则,领域层就可以不再依赖于基础设施层,基础设施层通过注入持久化的实现就完成了对领域层的解耦,采用依赖注入原则的新分层架构模型就变成如下所示:


DIP分层

采用了依赖注入方式后,其实可以发现事实上已经没有分层概念了。无论高层还是底层,实际只依赖于抽象,整个分层好像被推平了,这就引入下一个架构六边形架构。

六边形架构(Hexagonal architecture)

六边形架构是Alistair Cockburn在2005年提出,解决了传统的分层架构所带来的问题,实际上它也是一种分层架构,只不过不是上下或左右,而是变成了内部和外部。在《实现领域驱动设计》一书中,作者将六边形架构应用到领域驱动设计的实现,六边形的内部代表了application和domain层。外部代表应用的驱动逻辑、基础设施或其他应用。内部通过端口和外部系统通信,端口代表了一定协议,以API呈现。

六边形架构

六边形架构

按照领域分层的模型,在应用层和领域层内置后,一个典型的六边形架构应用有两个端口,一个端口对应用户接口层,用于应用控制,一个对应数据访问层,用于数据获取和持久化。每个端口都可以对应几个适配器,该应用可以被自动化测试,系统层面的回归测试,用户交互操作,远程HTTP调用,REST调用或者其他。在数据方面,通过配置使用外部的数据库,可以是Oracle数据库,mock的数据库,测试数据库或生产数据库,从而实现应用和外部数据库的解耦。
另外值得一提的是,在六边形架构中,自动化测试和用户具有同等的地位,在实现用户界面的同时就需要考虑自动化测试。它们对应相同的端口。六边形架构不仅让自动化测试这件事情成为设计第一要素,同时自动化测试也保证应用逻辑不会泄露到用户界面,在技术上保证了层次的分界。
使用六边形架构的时候,我们应该根据用例来设计应用程序,而不是需要支持的客户数量来设计。任何客户都可能向不同的端口发出请求,但是所有的适配器都使用相同的API。
六边形架构的功能非常强大,可以作为基层架构并用于支持系统的其他架构。

面向服务架构

SOA

REST

REST表述性状态传递( Representational State Transfer),是 Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。
REST全称是 Resource Representational State Transfer,通俗来讲就是:资源在网络中以某种表现形式进行状态转移。分解开来:

  1. Resource:资源,即数据(前面说过网络的核心)。比如 newsfeed,friends等;
  2. Representational:某种表现形式,比如用JSON,XML,JPEG等;
  3. State Transfer:状态变化。通过HTTP动词实现。

作为一种被广泛使用,甚至被滥用的架构流行语,很多人了解REST是把它作为一种Web通信协议,但实际REST是这是一种架构风格。架构风格之于架构就像设计模式之于设计一样。它将不同架构实现所共有的东西抽象出来,使得我们在谈及到架构时不至于陷人技术细节中。

作为一种架构风格,就需要遵循其提出的一系列架构级约束。REST的约束有:

  • 客户-服务器(Client-Server),通信只能由客户端单方面发起,表现为请求-响应的形式。
  • 无状态(Stateless) 通信的会话状态(Session State)应该全部由客户端负责维护。
  • 缓存(Cache) 响应内容可以在通信链的某处被缓存,以改善网络效率。
  • 统一接口(Uniform Interface) 通信链的组件之间通过统一的接口相互通信,以提高交互的可见性。
  • 分层系统(Layered System)通过限制组件的行为(即,每个组件只能“看到”与其交互的紧邻层),将架构分解为若干等级的层。
  • 按需代码(Code-On-Demand,可选)

如果一个系统满足了上面所列出的约束,那么该系统就被称为是RESTful的。当然一旦遵循了以上约束,也意味着这个系统就会享受到这种架构风格带来的好处。实际上HTTP1.1也正是基于REST架构风格来设计的,REST架构也是Web之所以取得成功的技术架构方面因素的总结。

符合REST原则的系统将具有更好的松耦合性。通常来讲,添加新资源并在已有资源中创建到新资源的链接是非常简单的。另外基于 REST的系统也是非常容易理解的,因为此时系统被分为很多较小的资源块,每一个资源块都可以独立地测试和调试,并且每一个资源块都表示了一个可重用的人口点。 HTTP设计本身以及URI成熟的重写与缓存机制使得 RESTful HTTP成为一种不错的架构选择,该架构具有很好的松耦合性和可伸缩性。

REST和DDD

领域模型通过REST直接暴露给外界并不被推荐,要将 DDD与 RESTful HTTP合并起来使用,推荐的方式是:为系统接口层单独创建一个限界上下文,再在此上下文中通过适当的策略来访问实际的核心模型。它将系统接口看作一个整体,通过资源抽象将系统功能暴露给外界,而不是通过服务或者远程接口。

另一种方法用于需要使用标准媒体类型的时候。如果某种媒体类型并不用于支持单个系统接口,而是用于一组相似的客户端.服务器交互场景,此时我们可以创建一个领域模型来处理每一种媒体类型。这样的领域模型甚至可以在服务器和客户端之间进行重用。
这也是一种由外向里的、横切式的方法。在上面提到的工作组例子中,有多种常用的格式可以用于领域模型。比如 iCal格式(一种标准的互联网日历格式)。我们首先选择一种媒体类型,即 iCal,然后再根据这种格式创建领域模型。该模型可以用于任何能够理解 ical格式的系统,比如服务器程序,或者 Android客户端。在采用这种方法时,服务器需要处理多种类型的媒体类型,而同一种媒体类型又可以用于多个服务器。

如何在以上两种方法之间进行选取呢?这在很大程度上取决于系统设计者对可重用性上的要求。第一种方法比较适合更加专属的系统,而第二种方法更适合那些通用的系统。

两个建议:

  • 设计好REST的API接口后,通过Application层去顺序调用合适的领域对象,这也正是Application层的价值所在。
  • 不要盲目的遵循教条的理论。我们应该尽可能遵循各种理论和最佳实践,但是如果不行的时候就先把这些放到一边去(当然这需要在慎重考虑后)。

参考资料

DDD分层架构的三种模式
微服务架构基础——解读六边形架构
SOA面向服务架构

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,440评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,814评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,427评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,710评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,625评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,511评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,162评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,311评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,262评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,278评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,989评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,583评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,664评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,904评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,274评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,856评论 2 339

推荐阅读更多精彩内容