作者:京東科技 康志興
前言
從強調內外隔離的六邊形架構,逐漸發展衍生出的層層遞進、注重領域模型的洋蔥架構,再到和DDD完美契合的整潔架構,架構風格的不斷演進,其實就是為了適應軟體需求越來越復雜的特點,
可以看到,越現代的架構風格越傾向于清晰的職責定位,且讓領域模型成為架構的核心,
基于這些架構風格,在軟體架構設計程序中又有非常多的架構分層模型,
傳統三層架構
傳統服務通常使用三層架構:
? 門面層:作為服務暴露的入口,處理所有的外部請求,部分情況下,門面層甚至不需要單獨定義物件而是直接使用服務層的物體定義,
? 服務層:作為核心業務層,包含所有業務邏輯,并對基礎層能力進行簡單組合提供一定的能力復用,通常服務層會進行物體定義來防止下層物件體直接暴露給外部服務,導致底層任何變化都有可能直接傳遞到外部,非常不穩定,
? 基礎層:用來存放dao和外部rpc服務的封裝,二者可以拆分為不同的module,也可合二為一,以不同package進行隔離,
三層架構特點就是簡單,適用于一些無復雜業務場景的小型應用,或者“資料不可變”作為基礎原則的DOP(面向資料編程)服務,
但是當業務場景稍微復雜一些、呼叫層級較多時,可復用性、可維護性就都非常差了,很多代碼都耦合在一起,牽一發動全身,
DDD架構
DDD架構可以看做是整潔架構的一種實作,分層職責如下:
? 適配層:用來做外部不同端請求的配接器,隔離不同端的協議差異,包裝不同端不同樣式的回應體,
? 應用層:用例、任務入口、訊息佇列監聽均在這一層,可以理解為業務流程的入口,通過聚合根的構造執行相應的命令操作,
? 領域服務層:包含核心的領域服務定義,并定義了gateway來做一層依賴倒置,使基礎設施層僅做實作,
? 基礎設施層包含一切基礎能力:資料庫、ES、遠程呼叫封裝等等,
優點
? 核心穩定:領域模型在依賴鏈上是頂層角色,不依賴任何其他模塊,所以極其穩定,其他任何業務域、存盤、邊緣能力的變化都不會對領域模型造成影響,
? 敏捷:適合不同團隊一起開發和維護而不會產生沖突,
? 可拆分:當有屆背景關系隨著演進逐漸膨脹時,很容易拆分成微服務,
? 可擴展:添加新的功能非常簡單,從而使得開發人員能夠更快的部署和調整,
? 可演進:良好的可測驗性帶來非常低的重構成本,不會隨著不斷迭代導致專案成為難以修改的“大泥球”,
如此多的優點自然帶來明確的缺點
? 專業性要求較高:需要對業務、架構原則理解深刻的人員進行設計和維護,不恰當的領域模型將使后續迭代極為痛苦,
? 開發成本高:復雜的架構設計,更多的架構分層,自然帶來代碼行數的指數級增長,尤其是專案前期的開發任務變得例外繁重,
? 不再適合簡單的業務場景:實作一個簡單的CRUD顯得過于復雜,
? 改變決策困難:嘗試使用整潔架構需要和團隊的管理層和其他成員達成一致,這往往需要非常強大的說服力,如果在架構演程序序中想切換回其他架構模式也十分困難,幾乎是整個專案級別的重構作業,
簡單的微服務分層架構
基于六邊形架構規范的介面適配原則和防腐理念,同時借鑒了CQRS模式的優點,我們定義了一個簡單的微服務分層架構,
分層定義如下:
? 門面層:作為程式的入口,通過包隔離來存放JSF服務、Rest服務、定時任務和MQ消費,其中對外提供服務的介面定義存放在單獨的api包中,該層的請求定義命名以Request結尾,回應體命名以Response結尾,
? 領域服務層:每一個領域服務存放在單獨的module中,并通過單獨的api包對外暴露能力,該層的命令請求定義命名以Command結尾,查詢請求定義命名以Query結尾,回應體命名以Dto結尾,
? 基礎設施層:存放資料庫、ES、遠程呼叫服務的封裝,該層的持久化資料定義命名以Po結尾,遠程命令服務入參命名以RpcCommand結尾,遠程查詢服務入參命名以RpcQuery結尾,回應體命名以RpcDto結尾,
最佳實踐
-
命令服務必須訪問領域服務層,允許簡單查詢直接呼叫基礎設施層,
-
引數校驗、請求出入參日志、審計日志記錄、TraceID預埋、例外處理等非核心業務能力均由公共組件完成,減少專案內部的邊緣能力代碼,
-
由于在門面層進行統一的例外處理,非必要時無需在專案中進行大面積的try-catch,讓代碼更清爽,
-
實際開發程序中,門面層、領域服務層和基礎設施層均有各自的物體定義,跨層呼叫的物件體轉換使用MapStruct組件來減少手寫映射代碼的作業量,
-
資料層使用Fluent-Mybatis,最大好處是減少后期迭代中,資料物件增減欄位時修改Mapper的成本,
優點
1. 開發效率
簡單的業務開發程序中,相比較書寫核心業務邏輯,更多的作業量幾乎都是來自處理跨層呼叫時物件轉換和Mapper定義,通過MapStruct和Fluent-Mybatis等組件的使用(也許再加上GitHub Copilot??),撰寫一個物體的增刪改查介面基本在5分鐘內搞定,省下來的時間可以多走讀兩遍代碼或者多寫幾個分支的測驗用例,也算是降本增效了,
2. 服務隔離
通過module隔離不同的領域服務,降低不同領域服務之間的耦合程度,
3. 外部服務防腐
遠程呼叫統一封裝在基礎設施層中,降低外部變化對系統內部的影響,
缺點
- 基礎設施層的物體作為頂層依賴
由于對基礎設施層的依賴沒有通過api包進行隔離,所以基礎設施層的物件會直接暴露在領域服務層和門面層,對此可以通過使用ArchUnit組件進行架構防腐,
如果需要定義完善的領域物體充血模型,建議參考DDD架構定義gateway層來進行基礎設施層的依賴倒置,
最后
軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可,
架構不只是作業,更是一門藝術,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/550473.html
標籤:其他
下一篇:05單件模式