DDD 六邊形架構入門
經營傳統農場絕對是一場噩夢。你必須餵食動物,把它們趕出去,安排獸醫的拜訪,種植莊稼,驅趕害蟲,並同時處理數百項其他任務。
把所有東西都放在正確的地方一定是一份全職工作。雞無意識地四處遊蕩,被狐狸搶購一空,羊跳籬笆,荊棘叢生侵入你的土地。
分離農場的不同功能區域是其成功管理的關鍵。讓那些雞遠離玉米地,並豎起堅固的柵欄以阻止奶牛離開城鎮。
Clean 分離
同樣,在任何重要的軟件項目中,一半的戰鬥都是管理複雜性。事實上,您可能會爭辯說,任何軟件專業人員的主要作用是馴服複雜性,以使我們工作的系統_易於更改_。
劃分應用程序的功能區域是使其易於管理的關鍵。我們不想將持久性框架的關注點與核心業務邏輯、用戶界面或代碼中發生的任何其他事情混淆。根據_單一職責原則_,我們希望將因相同原因而發生變化的事物聚集在一起,並將因不同原因而發生變化的事物分開。這樣做可以簡化代碼的推理、測試和簡單的舊維護。
將因相同原因而發生變化的事物聚集在一起。將那些因不同原因而改變的東西分開——單一職責原則
分層架構
管理關注點分離的最常見模式之一是使用分層架構。
來自 Eric Evans 的領域驅動設計
這些層捕獲應用程序的相關部分。出於類似原因而更改的部分保持在一起(內聚),並與程序中關聯度較低的部分分離(解耦)。任何層都應該只依賴於它自己的一部分或它下面的層。這使我們能夠在應用程序的一個領域工作,而不必擔心其他問題。
這是一種易於理解且廣泛使用的模式,對於許多軟件來說非常有用。然而,它並非沒有問題。
當層變成千層面
儘管分層架構有明確的分離,但邊界並不總是得到很好的維護。
無論是否有意識,開發人員偶爾會模糊架構的線條以將功能推出門外。例如,使用數據庫存儲過程來執行業務級任務會將關注點分散到多個層。當您陷入困境時,這可能並不明顯,因此幾個月後,這些層開始相互滲透,混合在一起,破壞了架構的許多好處。
此外,分層方法暗示了架構的單一維度。如果您需要的不僅僅是用戶界面來驅動應用程序——添加 CLI、REST API 或事件流作爲輸入怎麼辦?當然,您可以將它們添加到分層架構中,但它們不太適合一維心智模型。
驅動和被驅動
讓我們翻轉一個分層架構。
用戶界面_驅動_應用程序。它是所有交互的源泉。軟件的核心(領域及其應用程序服務)對_驅動_端的交互做出反應,並依賴於較低層來幫助它滿足這些請求。我們可以說那些較低(最右邊)的層是被_驅動的_。
這裏存在一個有趣的對稱性。_驅動_端和被_驅動_端都是與我們應用程序_之外_的事物的交互。它們本身並不提供核心價值——這是領域的工作——而是幫助我們將核心價值傳遞給世界。
軟件提供的價值保存在這些中間層中,我們應該使與它們的接口——包括測試——儘可能乾淨。同樣,我們希望防止外部擔憂侵犯我們軟件的核心目的。
六邊形架構 / 端口和適配器
既然我們已經斷言我們的應用程序的中心是最有價值的部分,我們可以改變我們的架構來保護它。
我們要做的關鍵改變是讓依賴項向內——在域——而不是像以前一樣指向鏈中的下一層。這樣做可以讓我們根據需要注入細節(數據庫、用戶界面等),並使我們的核心抽象保持乾淨和不受影響。
抽象不應該依賴於細節。細節(具體實現)應該依賴於抽象——依賴倒置原則
應用和領域
我們從領域模型開始。我們將其包裝在應用程序服務(與我們的應用程序層相同)中,作爲我們軟件的核心。
這個捆綁包通常與技術無關——它只涉及我們的軟件旨在解決的問題。這使得推理、與領域專家討論和測試變得更加簡單。隨着我們的發展,我們不再在頭腦中處理正交問題。
通往外部世界的端口
當然,我們需要在這個核心中插入一些東西,否則它完全沒用。這就是端口的用武之地。
端口只是一個接口。在_駕駛_方面,這個界面是調用我們的軟件,詢問它的問題——例如,將 10 美元存入我的銀行賬戶。在_驅動_端,我們有接口將被域調用以使用外部資源——數據庫、外部 API 等。
六邊形架構的 “六邊形” 部分是爲了證明一個應用程序可能有許多不同的東西插入這些端口。我們可以使用 GUI 和測試工具驅動軟件,或者在後端插入不同的數據庫技術。
使用適配器插入
端口只是接口,所以我們需要一些東西來實現它們。我們要與之交互的系統不會兼容,因此我們需要使用適配器模式從一個域轉換到另一個域。
每個端口都可以通過適配器安裝,以允許外部系統與我們的應用程序對話,或者(在右側)讓我們的應用程序與外部系統對話。
如前所述,這些適配器被_注入_,以便界面或數據表爲中心的抽象不依賴於它之外的細節。
結論
這是六邊形結構的最終形式。我們已經從以層爲幌子的善意但最終耦合的架構轉變爲更清潔、更健壯的架構。
端口和適配器使我們能夠在系統中保持牢固的邊界,將不相關的事物很好地劃分。我們在六邊形周圍有多個端口這一事實允許我們在每個端口插入多個系統,並通過測試適配器確保我們不會意外地將內核與外層耦合(通過三角測量)。
當然,一切都是有代價的。需要定義端口接口,並且需要開發適配器以在外層和內層的語義之間進行轉換。這並非完全微不足道,並且確實帶有一些維護開銷 / 樣板。
對於簡單的軟件,六邊形架構幾乎可以肯定是矯枉過正。不過,對於更復雜的應用程序——尤其是那些具有繁忙領域或遵循_領域驅動設計_的應用程序——它可能是您工具箱中非常有價值的補充,有助於保持軟件易於理解和易於發展。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/g_WM1ivKWvtZsMAfEZkCcQ