分層架構的一個重要原則是:每層只能與位於其下方的層發生耦合。
分層架構分兩種:一種是嚴格分層架構,規定某層只能與直接位於其下方的層發生耦合;另一種是鬆散分層架構,允許任意上方層與任意下方層發生耦合。
下圖是一個典型的DDD傳統分層架構。
以上分層架構中各層都有自己的職責:
使用者介面層負責處理使用者請求和使用者顯示;
應用層實現不同業務場景下的用例或業務流程。其中應用服務通常接收來自使用者介面層的請求,然後通過資源庫獲取聚合範例,最後執行相應的命令操作,如下範例:
// 應用層的用例
public void cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
// 領域層的業務邏輯
order.cancel()
orderRepository.save(order);
}
領域層實現系統的核心業務邏輯,主要包含基於DDD業務建模產生的領域模型,這裡的業務邏輯不同於應用層中的業務流程,如上程式碼範例;
基礎設施層為其它各層提供通用的技術和基礎服務,比如資料持久化功能。
DDD中資源庫(Repository)用來獲取或持久化聚合,每個聚合都擁有一個對應的資源庫。由此可見資源庫應該和聚合位於同一層,資源庫介面定義應該位於領域層,而資源庫介面實現需要依賴基礎設施層的持久化機制,此時資源庫介面實現放在哪一層對傳統分層架構來說是個問題。
如果把資源庫介面實現放在基礎設施層,那麼基礎設施層就會向上依賴領域層,這樣就違反了分層架構的原則:每層只能與位於其下方的層發生耦合。
或者可以放在領域層,但是這樣會使領域層依賴資料持久化的實現細節,導致領域層不再是一個穩定層。
也可以放在應用層,不過和放在領域層會有同樣的問題。
那有沒有更好的方式呢?
有,採用依賴倒置,打破分層架構原則。
依賴倒置(或依賴反轉)原則(Dependency inversion principle,DIP),由Bob大叔提出,其定義如下:
高層模組不應該依賴於低層模組,兩者都應該依賴於抽象。 抽象不應該依賴於細節,細節應該依賴於抽象。
我們把資源庫介面實現放在基礎設施層,讓基礎設施層向上依賴領域層。雖然這樣違背了分層架構原則,但是卻符合依賴倒置原則:領域層(高層模組)不依賴基礎設施層(低層模組),兩者都依賴於資源庫介面(抽象)。採用了依賴倒置後,同時調整下基礎設施層位置,此時分層架構如下圖:
分層架構採用依賴倒置原則後,實際上已經不存在分層的概念了。無論是高層還是低層,都只依賴於抽象,好像把整個分層架構給推平了一樣。推平後的分層架構如下圖:
給推平的分層架構補上左側對稱的另一半,其結果就類似六邊形架構,如下圖是六邊形架構。
六邊形架構也叫埠和介面卡。在這種架構中,針對系統輸入輸出的不同互動方式,比如http、rpc、mq、資料持久化等,都有與之對應的介面卡,介面卡又通過應用層API與內部進行互動。
六邊形架構讓應用程式能夠以一致的方式被使用者、程式、自動化測試、批次處理指令碼所驅動,而且能夠讓應用程式的邊界更加清晰。有關六邊形架構的詳細資訊可以檢視 六邊形架構原文翻譯
整潔架構是Bob大叔在其《架構整潔之道》一書中,對六邊形架構和其他類似架構做了總結和抽象之後,提出的一種架構設計理念。
書中總結出,六邊形架構和其他類似架構設計出來的系統,都具有相同的特點:
獨立於框架:這些系統的架構並不依賴某個功能豐富的框架之中的某個函數。框架可以被當成工具來使用,但不需要讓系統來適應框架。 可被測試:這些系統的業務邏輯可以脫離UI、資料庫、Web服務以及其他的外部元素來進行測試。 獨立於UI:這些系統的UI變更起來很容易,不需要修改其他的系統部分。 獨立於資料庫:我們可以輕易將這些系統使用的Oracle、SQL Server替換成Mongo、BigTable、CouchDB之類的資料庫。因 為業務邏輯與資料庫之間已經完成了解耦。 獨立於任何外部機構:這些系統的業務邏輯並不需要知道任何其他外部介面的存在。
綜合以上所有架構的設計理念,Bob大叔提出了整潔架構設計理念,如下圖。
以上圖中同心圓分別代表了軟體系統的不同層次,通常越靠近中心,其所在的軟體層次就越高。
整潔架構規定了層之間的依賴關係規則:內層(高層)不依賴外層(低層),六邊形架構層之間的依賴關係也遵從此規則。
至此可以認為整潔架構是一種架構設計的指導思想,六邊形架構是整潔架構的一種具體的架構設計。
採用依賴倒置原則後的分層架構和六邊形架構,實際上都符合整潔架構設計理念。但是六邊形架構中使用埠與介面卡,讓應用程式能夠以一致的方式被使用者、程式、自動化測試、批次處理指令碼所驅動,同時能夠讓應用程式邊界更加清晰,從而能更好地防止領域層和應用層邏輯洩露到外層。
1.《實現領域驅動設計》
2.《架構整潔之道》
作者:京東零售 加文雄
來源:京東雲開發者社群