六角架构学的三个原则和技术1

电子说

1.3w人已加入

描述

Hexagonal Architecture于2005年由Alistair Cockburn撰写,是一个具有许多优势的软件架构,自2015年以来又重新引起了人们的兴趣。

六角架构的初衷是:

允许应用程序同样由用户,程序,自动化测试或批处理脚本驱动,并与最终的运行时设备和数据库隔离开发和测试。

为了探索通过自动化测试引导应用程序的好处,或者从数据库中单独开发和测试,我们建议您阅读我们最近发布的测试金字塔上的这一系列博客文章:实践中的测试金字塔。

承诺非常有吸引力,它还有另一个有益效果:它允许隔离应用程序的核心业务,并自动测试其行为,而不依赖于其他任何事情。这可能是该架构引起域驱动设计(DDD)从业者关注的原因。但要小心,DDD和六边形结构是两个相当不同的概念,它们可以相互加强,但不一定一起使用。但这是另一个时间的主题!

最后,这种架构设置起来并不复杂。它基于一些简单的规则和原则。让我们探索这些原则,看看它们在实践中的含义。

  • 六角架构原理
  • 细节:内部和外部的代码如何组织?
  • 细节:运行时
  • 细节:右侧的依赖性反转
  • 细节:为什么左边有借口?
  • 六角形结构测试
  • 更进一步
  • 参考

六角架构学原理

六边形体系结构基于三个原则和技术:

  • 明确区分应用程序,域和基础结构
  • 依赖关系从应用程序和基础结构到域
  • 我们使用端口和适配器隔离边界

词汇说明:在本文的其余部分中,将使用“应用程序”,“域”和“基础结构”等字样。这些词不是来自原始文章,而是来自领域驱动设计从业者频繁使用六边形体系结构。作为参考,原始文章的文字在下面的部分中说明。

原则:单独的应用程序,域和基础结构

第一个原则是明确地将代码分成三个大的形式化区域。

脚本驱动

左侧,应用程序端

这是用户或外部程序与应用程序交互的一面。它包含允许这些交互的代码。通常,您的用户界面代码,API的HTTP路由,以及使用您的应用程序的程序的JSON序列化都在这里。

这是我们找到驱动领域的演员的一面。

注意:Alistair Cockburn谈论应用程序方面的左侧或用户侧。

领域,在中心

这是我们想要从左侧和右侧隔离的部分。它包含所有关注和实现业务逻辑的代码。业务词汇和纯粹的业务逻辑,与解决您的应用程序的具体问题,使其丰富和具体的所有内容相关联,处于中心位置。理想情况下,不知道如何编码的领域专家可以阅读本部分中的一段代码并指出您的不一致(真实的故事,这些都可能发生在您身上!)。

注意:Alistair Cockburn谈论域的中心或业务逻辑。

右侧,基础设施方面

在这里,我们可以找到您的应用程序需要什么,它驱动的工作。它包含必要的基础结构详细信息,例如与数据库交互的代码,调用文件系统或处理对您所依赖的其他应用程序的HTTP调用的代码。

这是我们找到由领域管理的演员的一面。

注意:Alistair Cockburn谈论基础设施方面的右侧或服务器端。

以下原则将允许在应用程序,域和基础结构之间实现这种逻辑分离。

为什么这很重要?

这种分离的第一个重要特征是它将问题分开。在任何时候,您都可以选择专注于单个逻辑,几乎独立于其他两个逻辑:应用程序逻辑,业务逻辑或基础架构逻辑。它们在不混合的情况下更容易理解,并且每个逻辑的约束对其他逻辑的影响较小。

另一个特点是我们将业务逻辑放在代码的最前端。它可以在目录或模块中隔离,以使其对所有开发人员都明确。它可以在不承担程序其余部分的认知负荷的情况下进行定义,改进和测试。这很重要,因为最终,开发人员对生产中的业务有了解。

最后,在自动化测试方面(我们将在下面看到),我们将以合理的努力成功进行测试:

  1. 整个域单独,
  2. 在Infrastructure端独立地集成Application和Domain
  3. 在应用程序端独立地集成域和基础架构

插图:应用程序的一个小例子

为了更具体地说明这些原则,我们将使用Alistair期间在“Hexagon”事件中使用的小例子,该事件由Thomas Pierrain(@tpierrain)和Alistair Cockburn(@TotherAlistair)于2017年提出。注意:您可以在文章末尾找到视频和事件代码。

这个小应用程序的目的是提供一个命令行程序,将诗歌写入控制台的标准输出。

此应用程序的预期输出示例:

$ ./printPoem
Here is some poem:
I want to sleep
Swat the files
Softly, please.
-- Masaoka Shiki (1867 - 1902)
Type enter to exit...

为了正确地说明三个区域(应用程序,域,基础设施),此应用程序将在外部系统中搜索诗歌:文件。我们还可以将此应用程序连接到数据库,原则是相同的。

在这种情况下,我们如何应用这第一个原则,即分成三个区域?如何在左侧(什么驱动它),在中心(核心业务)和右侧(什么是驱动)分发?

脚本驱动

应用方面

从用户的角度来看,程序是作为控制台应用程序呈现的。因此,控制台的概念将位于应用程序端的左侧。通过控制台,用户将驱动领域。

基础设施方面

从技术上讲,在我们的例子中,诗歌存储在一个文件中。这个文件的概念将在基础设施方面的右侧找到。该企业将通过试用这一右侧来提出其诗歌的要求,具体由PoetryLibraryFileAdapter实施。

在这里,如上所述,我们可以轻松地交换我们的诗歌来源(文件,数据库,网络服务......)。因此,作为文件的源的实际实现是技术细节(也称为技术实现细节)。

领域方面

在这种情况下,我们的核心业务是对用户有价值的东西,就是阅读诗歌的概念。我们可以使用PoetryReader类在代码中实现这个概念

应用→域交互

从业务角度来看,请求是来自控制台应用程序还是其他应用程序无关紧要,这是我们希望能够抽象的技术细节。这恰恰是最初的意图之一:“由用户和测试一起驱动”。因此,域中没有控制台的概念。然而,我们的应用程序允许从用户的角度(=它提供的服务)来请求诗歌。我们将在域中找到这一概念(由IRequestVerses实现),这将允许应用程序端与域进行交互。

域→基础设施互动

同样,从域的角度来看,诗歌是来自文件还是数据库并不重要,我们希望能够独立于外部系统测试我们的应用程序。域中没有文件概念。要运作,领域仍然需要得到诗歌。我们发现这个概念是以IObtainPoems界面的形式在Domain中获取诗歌。正是这种获取诗歌的概念将允许域与基础设施方面进行交互。

注意:从这里,当您阅读图表时,您可以开始观察显示类之间关系的箭头。实线箭头表示调用或组合交互。没有填充的箭头表示继承关系(如在UML中)。但不需要立即分析所有内容,我们稍后会详细探讨。

注意:名称IRequestVerses和IObtainPoems代表许多接口,我们将按照原则来讨论它们。对于轶事,使用“i”启动接口名称的约定不再流行,但Thomas Pierrain将接口名称作为第一人称单数的句子读取。IRequestVerses写道:例如我请求经文。我喜欢这个主意。

原则:依赖进入内部

这是实现目标的基本原则。我们已经开始在先前的原则中看到这一点。

脚本驱动

Principle: Dependencies go to the Domain

程序可以通过控制台和测试来控制,域中没有控制台的概念。域不依赖于应用程序端,应用程序端依赖于域。应用程序端(ConsoleAdapter)依赖于诗请求的概念,IRequestVerses(它定义了用户方面的通用“诗请求”机制)。

同样,程序可以独立于其外部系统进行测试,Domain不依赖于Infrastructure方面,相反,它是依赖于Domain的Infrastructure方面,通过获取诗歌的概念,IObtainPoems。从技术上讲,基础结构方面的类将继承Domain中定义的接口并实现它,我们将在下面详细讨论它以讨论依赖性反转。

内在和外在

如果我们将依赖关系(<<>)视为箭头,那么这个原则将中心域定义为内部,将其他所有内容定义为外部(见图)。当我们讨论六边形结构时,我们经常发现内部和外部的这些概念。它甚至可以成为记忆和传播的基本点:依赖关系进入内部。

换句话说,一切都取决于域,域不依赖于任何东西。Alistair Cockburn坚持内部和外部的这种划分,这比应用和基础设施之间的差异更能解决最初的问题。

脚本驱动

原理:边界与接口隔离

脚本驱动

总而言之,应用程序代码通过业务代码中定义的接口(此处为IRequestVerses)来驱动业务代码。业务代码通过业务代码(IObtainPoems)中定义的接口驱动基础架构。这些接口充当内部和外部之间的显式绝缘体。

隐喻:端口和适配器

六边形体系结构使用端口和适配器的比喻来表示内部和外部之间的交互。图像是域定义了端口,如果它们遵循端口定义的规范,则可以在其上交换连接所有类型的适配器。

脚本驱动

例如,我们可以设想Domain的一个端口,我们将在单元测试期间连接硬编码数据源,或者在集成测试中连接真实数据库。只需在Infrastructure端编写相应的实现和适配器,Domain就不会受到此更改的影响。

由业务代码定义的这些接口隔离并允许与外部世界的交互,这些接口是Ports&Adapters隐喻的端口。注意:如前所述,端口由业务定义,因此它们位于内部。

另一方面,适配器表示外部代码在端口与应用程序代码或基础结构的其余部分之间形成粘合剂。这里,适配器分别是ConsoleAdapter和PoetryLibraryFileAdapter。这些适配器在外面。

另一个隐喻:六角形

脚本驱动

正如我们在上图中看到的那样,另一个为这个架构命名的比喻是六边形。为什么是六边形?主要原因是它是一个易于绘制的形状,为图表上的多个端口和适配器留出了空间。事实证明,即使六边形最终是轶事,六边形体系结构的表达也比端口和适配器模式更受欢迎。可能是因为听起来更好?

理论部分已经结束,没有其他原则:对于其他一切我们完全自由。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分