Hexagonal Architecture于2005年由Alistair Cockburn撰寫,是一個具有許多優(yōu)勢的軟件架構,自2015年以來又重新引起了人們的興趣。
六角架構的初衷是:
允許應用程序同樣由用戶,程序,自動化測試或批處理腳本驅動,并與最終的運行時設備和數(shù)據(jù)庫隔離開發(fā)和測試。
為了探索通過自動化測試引導應用程序的好處,或者從數(shù)據(jù)庫中單獨開發(fā)和測試,我們建議您閱讀我們最近發(fā)布的測試金字塔上的這一系列博客文章:實踐中的測試金字塔。
承諾非常有吸引力,它還有另一個有益效果:它允許隔離應用程序的核心業(yè)務,并自動測試其行為,而不依賴于其他任何事情。這可能是該架構引起域驅動設計(DDD)從業(yè)者關注的原因。但要小心,DDD和六邊形結構是兩個相當不同的概念,它們可以相互加強,但不一定一起使用。但這是另一個時間的主題!
最后,這種架構設置起來并不復雜。它基于一些簡單的規(guī)則和原則。讓我們探索這些原則,看看它們在實踐中的含義。
- 六角架構原理
- 細節(jié):內部和外部的代碼如何組織?
- 細節(jié):運行時
- 細節(jié):右側的依賴性反轉
- 細節(jié):為什么左邊有借口?
- 六角形結構測試
- 更進一步
- 參考
六角架構學原理
六邊形體系結構基于三個原則和技術:
- 明確區(qū)分應用程序,域和基礎結構
- 依賴關系從應用程序和基礎結構到域
- 我們使用端口和適配器隔離邊界
詞匯說明:在本文的其余部分中,將使用“應用程序”,“域”和“基礎結構”等字樣。這些詞不是來自原始文章,而是來自領域驅動設計從業(yè)者頻繁使用六邊形體系結構。作為參考,原始文章的文字在下面的部分中說明。
原則:單獨的應用程序,域和基礎結構
第一個原則是明確地將代碼分成三個大的形式化區(qū)域。
左側,應用程序端
這是用戶或外部程序與應用程序交互的一面。它包含允許這些交互的代碼。通常,您的用戶界面代碼,API的HTTP路由,以及使用您的應用程序的程序的JSON序列化都在這里。
這是我們找到驅動領域的演員的一面。
注意:Alistair Cockburn談論應用程序方面的左側或用戶側。
領域,在中心
這是我們想要從左側和右側隔離的部分。它包含所有關注和實現(xiàn)業(yè)務邏輯的代碼。業(yè)務詞匯和純粹的業(yè)務邏輯,與解決您的應用程序的具體問題,使其豐富和具體的所有內容相關聯(lián),處于中心位置。理想情況下,不知道如何編碼的領域專家可以閱讀本部分中的一段代碼并指出您的不一致(真實的故事,這些都可能發(fā)生在您身上?。?。
注意:Alistair Cockburn談論域的中心或業(yè)務邏輯。
右側,基礎設施方面
在這里,我們可以找到您的應用程序需要什么,它驅動的工作。它包含必要的基礎結構詳細信息,例如與數(shù)據(jù)庫交互的代碼,調用文件系統(tǒng)或處理對您所依賴的其他應用程序的HTTP調用的代碼。
這是我們找到由領域管理的演員的一面。
注意:Alistair Cockburn談論基礎設施方面的右側或服務器端。
以下原則將允許在應用程序,域和基礎結構之間實現(xiàn)這種邏輯分離。
為什么這很重要?
這種分離的第一個重要特征是它將問題分開。在任何時候,您都可以選擇專注于單個邏輯,幾乎獨立于其他兩個邏輯:應用程序邏輯,業(yè)務邏輯或基礎架構邏輯。它們在不混合的情況下更容易理解,并且每個邏輯的約束對其他邏輯的影響較小。
另一個特點是我們將業(yè)務邏輯放在代碼的最前端。它可以在目錄或模塊中隔離,以使其對所有開發(fā)人員都明確。它可以在不承擔程序其余部分的認知負荷的情況下進行定義,改進和測試。這很重要,因為最終,開發(fā)人員對生產(chǎn)中的業(yè)務有了解。
最后,在自動化測試方面(我們將在下面看到),我們將以合理的努力成功進行測試:
- 整個域單獨,
- 在Infrastructure端獨立地集成Application和Domain
- 在應用程序端獨立地集成域和基礎架構
插圖:應用程序的一個小例子
為了更具體地說明這些原則,我們將使用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...
為了正確地說明三個區(qū)域(應用程序,域,基礎設施),此應用程序將在外部系統(tǒng)中搜索詩歌:文件。我們還可以將此應用程序連接到數(shù)據(jù)庫,原則是相同的。
在這種情況下,我們如何應用這第一個原則,即分成三個區(qū)域?如何在左側(什么驅動它),在中心(核心業(yè)務)和右側(什么是驅動)分發(fā)?
應用方面
從用戶的角度來看,程序是作為控制臺應用程序呈現(xiàn)的。因此,控制臺的概念將位于應用程序端的左側。通過控制臺,用戶將驅動領域。
基礎設施方面
從技術上講,在我們的例子中,詩歌存儲在一個文件中。這個文件的概念將在基礎設施方面的右側找到。該企業(yè)將通過試用這一右側來提出其詩歌的要求,具體由PoetryLibraryFileAdapter實施。
在這里,如上所述,我們可以輕松地交換我們的詩歌來源(文件,數(shù)據(jù)庫,網(wǎng)絡服務......)。因此,作為文件的源的實際實現(xiàn)是技術細節(jié)(也稱為技術實現(xiàn)細節(jié))。
領域方面
在這種情況下,我們的核心業(yè)務是對用戶有價值的東西,就是閱讀詩歌的概念。我們可以使用PoetryReader類在代碼中實現(xiàn)這個概念
應用→域交互
從業(yè)務角度來看,請求是來自控制臺應用程序還是其他應用程序無關緊要,這是我們希望能夠抽象的技術細節(jié)。這恰恰是最初的意圖之一:“由用戶和測試一起驅動”。因此,域中沒有控制臺的概念。然而,我們的應用程序允許從用戶的角度(=它提供的服務)來請求詩歌。我們將在域中找到這一概念(由IRequestVerses實現(xiàn)),這將允許應用程序端與域進行交互。
域→基礎設施互動
同樣,從域的角度來看,詩歌是來自文件還是數(shù)據(jù)庫并不重要,我們希望能夠獨立于外部系統(tǒng)測試我們的應用程序。域中沒有文件概念。要運作,領域仍然需要得到詩歌。我們發(fā)現(xiàn)這個概念是以IObtainPoems界面的形式在Domain中獲取詩歌。正是這種獲取詩歌的概念將允許域與基礎設施方面進行交互。
注意:從這里,當您閱讀圖表時,您可以開始觀察顯示類之間關系的箭頭。實線箭頭表示調用或組合交互。沒有填充的箭頭表示繼承關系(如在UML中)。但不需要立即分析所有內容,我們稍后會詳細探討。
注意:名稱IRequestVerses和IObtainPoems代表許多接口,我們將按照原則來討論它們。對于軼事,使用“i”啟動接口名稱的約定不再流行,但Thomas Pierrain將接口名稱作為第一人稱單數(shù)的句子讀取。IRequestVerses寫道:例如我請求經(jīng)文。我喜歡這個主意。
原則:依賴進入內部
這是實現(xiàn)目標的基本原則。我們已經(jīng)開始在先前的原則中看到這一點。
Principle: Dependencies go to the Domain
程序可以通過控制臺和測試來控制,域中沒有控制臺的概念。域不依賴于應用程序端,應用程序端依賴于域。應用程序端(ConsoleAdapter)依賴于詩請求的概念,IRequestVerses(它定義了用戶方面的通用“詩請求”機制)。
同樣,程序可以獨立于其外部系統(tǒng)進行測試,Domain不依賴于Infrastructure方面,相反,它是依賴于Domain的Infrastructure方面,通過獲取詩歌的概念,IObtainPoems。從技術上講,基礎結構方面的類將繼承Domain中定義的接口并實現(xiàn)它,我們將在下面詳細討論它以討論依賴性反轉。
內在和外在
如果我們將依賴關系(<<>)視為箭頭,那么這個原則將中心域定義為內部,將其他所有內容定義為外部(見圖)。當我們討論六邊形結構時,我們經(jīng)常發(fā)現(xiàn)內部和外部的這些概念。它甚至可以成為記憶和傳播的基本點:依賴關系進入內部。
換句話說,一切都取決于域,域不依賴于任何東西。Alistair Cockburn堅持內部和外部的這種劃分,這比應用和基礎設施之間的差異更能解決最初的問題。
原理:邊界與接口隔離
總而言之,應用程序代碼通過業(yè)務代碼中定義的接口(此處為IRequestVerses)來驅動業(yè)務代碼。業(yè)務代碼通過業(yè)務代碼(IObtainPoems)中定義的接口驅動基礎架構。這些接口充當內部和外部之間的顯式絕緣體。
隱喻:端口和適配器
六邊形體系結構使用端口和適配器的比喻來表示內部和外部之間的交互。圖像是域定義了端口,如果它們遵循端口定義的規(guī)范,則可以在其上交換連接所有類型的適配器。
例如,我們可以設想Domain的一個端口,我們將在單元測試期間連接硬編碼數(shù)據(jù)源,或者在集成測試中連接真實數(shù)據(jù)庫。只需在Infrastructure端編寫相應的實現(xiàn)和適配器,Domain就不會受到此更改的影響。
由業(yè)務代碼定義的這些接口隔離并允許與外部世界的交互,這些接口是Ports&Adapters隱喻的端口。注意:如前所述,端口由業(yè)務定義,因此它們位于內部。
另一方面,適配器表示外部代碼在端口與應用程序代碼或基礎結構的其余部分之間形成粘合劑。這里,適配器分別是ConsoleAdapter和PoetryLibraryFileAdapter。這些適配器在外面。
另一個隱喻:六角形
正如我們在上圖中看到的那樣,另一個為這個架構命名的比喻是六邊形。為什么是六邊形?主要原因是它是一個易于繪制的形狀,為圖表上的多個端口和適配器留出了空間。事實證明,即使六邊形最終是軼事,六邊形體系結構的表達也比端口和適配器模式更受歡迎??赡苁且驗槁犉饋砀??
理論部分已經(jīng)結束,沒有其他原則:對于其他一切我們完全自由。
-
數(shù)據(jù)庫
+關注
關注
7文章
3845瀏覽量
64584 -
程序
+關注
關注
117文章
3795瀏覽量
81284 -
ddd
+關注
關注
0文章
23瀏覽量
2936 -
腳本驅動
+關注
關注
0文章
2瀏覽量
1369
發(fā)布評論請先 登錄
相關推薦
評論