神秘的六角形架構

聞數起舞 發佈 2020-06-21T14:36:15+00:00

如今,有關"六角形架構"的講座和博客文章不乏其人,但與原作者Alistar Cockburn最初提出的內容相比,它們中的許多人對六角形建築的看法要廣泛得多。 這會讓您感到不知所措,因此讓我們重新審視Alistar的原始想法,並消除一些困惑。

如今,有關"六角形架構"的講座和博客文章不乏其人,但與原作者Alistar Cockburn最初提出的內容相比,它們中的許多人對六角形建築的看法要廣泛得多。 這會讓您感到不知所措,因此讓我們重新審視Alistar的原始想法,並消除一些困惑。

首先,我們將看看傳統的分層架構,以與Alistar相同的方式開始。

分層架構

為了幫助我們應對軟體系統的複雜性,我們可以將它們劃分為不同的層(基於它們的抽象級別)。 層數沒有限制,但是作者通常建議三到四層。 在這裡,我們將使用藍色DDD書中的四層模型:

· 用戶介面層-向最終用戶顯示一些數據,以及最終用戶與系統進行交互的位置

· 應用層-協調域對象以執行最終用戶所需的任務

· 域層-包含所有業務邏輯,實體,事件和任何其他包含業務邏輯的對象類型

· 基礎架構層-支持以上各層的技術功能,例如 持久性或消息傳遞

層之間的通信僅向下進行。 在嚴格的方法中,一層只能與直接在其下面的層進行通信,而在寬鬆的方法中,一層可以與在層堆棧中其下的所有層進行通信。

傳統上,我們也將UI層稱為應用程式的前端,將基礎結構層稱為後端。 我選擇將"中間"部分稱為"核心",但如果您希望更具詩意,則也可以將其稱為"領域","業務邏輯",甚至可以稱為"軟體之心"。

系統的另一種觀點……

在Alistar看來,UI(我們的網絡客戶端)和資料庫之間沒有太大區別。 一個系統僅由兩個不同的部分組成:內部和外部。 內部是我們的核心,外部是UI和基礎結構所在的位置。

在這個新的系統視圖中,資料庫和Web客戶端不再是後端和前端。 他們都是一樣的-外在。

為了使Core與外界能夠互相交談,我們需要一種在它們使用的不同格式之間轉換數據的方法。 例如,我們的Web客戶端說HTTP,而我們的應用程式說PHP。 這就是為什麼還有另一個六角形包裹我們的核心。

在這個包裝器中,HTTP請求被轉換為我們的Core可以理解的PHP數據結構,反之亦然。 我們的資料庫也是如此。 我們需要一種將PHP數據結構(可能是對象)轉換為資料庫(可能是關係資料庫)格式的方法。 我們可以將這個包裝器稱為變壓器包裝器,這就是埠和適配器進入故事的地方。

埠和適配器

埠位於您的核心中,它們定義了如何與核心對話。 為此,您需要將適配器插入其中,以將外部格式的輸入轉換為埠接受的格式。

回到我們的應用程式。 在核心中,我們有一些用例。 如果您使用的是"命令查詢分離"方法,則可能是一條命令,或者它僅僅是一個Service類。 無論如何,我們的Web客戶端使用HTTP,而Core則使用PHP,因此我們需要將HTTP轉換為PHP,反之亦然。 因此,我們編寫了實現此目的的適配器。 這稱為控制器。

現在,我們想為外界提供與我們的核心對話的另一種方式。 也許使用CLI。 我們要做的就是編寫另一個適配器,該適配器將從CLI接收輸入並將其轉換為Core可以理解的相同PHP格式。

請注意,我們不需要接觸Core中的代碼來支持這種與我們系統對話的新方法。 Core非常高興地忽略了從外部世界與我們系統進行通信的多種不同方式(它只關心埠)。

該系統可以描述為一個核心,周圍是與外界的接口。 Alistar選擇將Core可視化為六邊形,因為它比五邊形更容易繪製,而且還因為它為我們提供了一個很好的視覺類比,其中Hexagon的一個邊緣代表與外界對話的原因之一。 第六沒有什麼神奇的-您可以具有n邊的形狀。

正如我們已經提到的,UI和基礎結構不再是後端和前端,而僅僅是外部。 因此,該系統視圖具有一定的對稱性。 但是,它也存在一定的不對稱性。 這意味著我們可以將埠分為兩組:驅動埠和從動埠。

埠是根據它們與Core通信的方式進行劃分的。 在驅動埠方面,它們是啟動與Core通信的驅動器(驅動我們的應用程式的行為)。 在驅動埠的情況下,由核心發起通信。

這就是Alistar最初提出的六角/埠和適配器架構。 他沒有提供有關如何在Core中構造代碼的說明。 許多人傾向於使用一些分層(洋蔥),並將其他架構與Hexagonal混合使用。 如果您想了解更多信息,我推薦Mattias Noback的這篇文章和Herberto Graca的這篇文章。

為什麼?

使用埠和適配器會給您的體系結構和設計增加一些複雜性(就像任何設計或體系結構模式一樣),因此,讓我們回顧一下此體系結構的主要優點是什麼。

延遲技術決策

我們如何開發軟體存在悖論。 在項目開始時,只要您的項目(領域)知識最少,我們就會做出重大的技術決策。 我們的領域知識只會隨著時間的推移而增長,因此,如果我們可以將這些技術決策推遲到將來某個時候能夠做出更明智的決策,那豈不是很好嗎?

使用埠和適配器,我們可以做到這一點。 假設您正在開始一個新項目,並且不確定應該使用哪種資料庫。 您可以使用純PHP編寫存儲庫適配器,以序列化您的實體並將其保存到文本文件中。 當然,此解決方案尚未投入生產,但可以讓您對域進行建模和測試,一旦對域有了更多的信心,就可以選擇資料庫並為其編寫實際的適配器。

交換技術

改變主意怎麼辦? 也許您意識到自己的選擇是錯誤的,或者只是想使用一種新的更好的技術。

在技術之間進行切換僅是為這些技術編寫新的適配器。 當然,這可能是艱苦的工作,但是它包括編寫新代碼,這總是比修改現有代碼更乾淨(以及為什麼"開放式封閉原則"如此好)。

可測性

在進行測試時,埠和適配器體系結構使我們能夠獨立於外部依賴項來測試應用程式。 在駕駛方面,我們可以將真實的適配器與測試適配器(我們的測試套件)交換,因此在Core中測試業務規則時,我們不需要通過UI進行討論,我們可以直接插入我們的測試套件 正中核心。

在驅動方面,我們可以將驅動適配器與測試適配器實現互換:

不要誤會我的意思。 您仍然應該編寫一些集成測試,以檢查您的實際基礎結構適配器是否正常工作,但是您不必每次在Core中測試某些業務規則時都測試該集成。

專注於核心

前面我們提到過,我們的核心非常高興地不知道外界-適配器。 我們核心唯一關心的是它提供給外部世界的埠。 這使您在開發Core時不受技術決策的影響,因此它可以真正由域驅動,而不是技術(框架)驅動。 現在,讓您的Core完全不受任何技術影響,可能有點理想,但是,此體系結構使您可以在域和業務邏輯與所使用的技術之間進行高級去耦。

什麼時候

那麼什麼時候應該使用埠和適配器體系結構? 好吧,一如既往,這取決於。 它的確增加了設計的複雜性,因此您需要確定它是否會帶來回報。 如果它帶來的好處對您來說很重要,那我就說吧。

(本文翻譯自Zvonimir Spajic的文章《Hexagonal Architecture Demystified》,參考:https://medium.com/we-are-madewithlove/hexagonal-architecture-demystified-fca986a85b20)

關鍵字: