領域驅動設計(DDD):分層架構

分層架構

在應用系統開發中,採用嚴格的、單一的、真正的的分層架構是可以的,但實際上我們已經採用了多種架構模式設計系統。當多種不同範式的架構混合在一起,你會不會出現“指鹿爲馬”的現象呢?

嚴格分層架構

在研究分層架構時,常通過概念性的定義或 OSI 七層應用(架構)來說明或解釋分層架構:

架構模式 Layers 有助於將應用程序劃分爲多組子任務,其中每組子任務都位於特定抽象層。

 

 

圖片取自《 POSA , Vol.I , p22 》

作爲一個在項目中引入分層架構的應用者,我們應該從更具體的規範來實現分層架構:

  • 相鄰層之間必須是單向耦合。上層只能依賴下層,下層永遠不能依賴上層。
  • 相鄰層之間必須是單向通信。上層去調用下層所提供的接口,下層永遠不能調用上層的接口。

《 POSA , Vol.I 》 爲我們提供了更多的實現規範,然而我要解決的是有關層的單向依賴問題。因爲有一些人在使用分層架構時,尤其是將分層架構引入到項目的目錄結構時,對於某些對象的劃分(從屬)存在一些混亂問題。

如果你有興趣瞭解更多分層架構的實現規範,可參考:《 POSA , Vol.I 》第二十六頁到第二十九頁相關知識。

鬆散分層架構(Relaxed Layered System)

在領域驅動設計(DDD)中採用的是鬆散分層架構,層間關係不那麼嚴格。每層都可能使用它下面所有層的服務,而不僅僅是下一層的服務。每層都可能是半透明的,這意味着有些服務只對上一層可見,而有些服務對上面的所有層都可見。

 

 

注意:鬆散分層架構依然是單向依賴,表明上層只能調用下層的服務,下層不能調用上層的服務。

繼承分層架構(Layering Through Inheritance)

同時在領域驅動設計(DDD)中也採用了繼承分層架構,高層繼承並實現低層接口。我們需要調整一下各層的順序,並且將基礎設施層移動到最高層。

 

 

注意:繼承分層架構依然是單向依賴,這也意味着領域層、應用層、表現層將不能依賴基礎設施層,相反基礎設施層可以依賴它們。

領域層 UserRepository 接口:

package com.mallfoundry.user.domain;

public interface UserRepository {
    User save(User user);
}

基礎設施層 JpaUserRepository 實現類:

package com.mallfoundry.user.infrastructure.persistence;

public class JpaUserRepository implements UserRepository {

    private final EntityManager entityManager;

    public JpaUserRepository(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public User save(User user) {
        return this.entityManager.merge(user);
    }
}

包(Package)與分層架構

我們確實使用包來劃分層級,但是包名並不能真正表示分層。

資源庫(Repository)

我們通常將資源庫的實現放置在基礎設施層,這是因爲我們採用了繼承分層架構。如果你現在採用的是鬆散分層架構,你需要將資源庫的實現放置在領域層。這是層的單向依賴原則所致,你不應該破壞這個原則。沒有任何理由需要破壞分層架構的單向依賴原則,除非你不採用分層架構。

三層或四層架構

 

 

我們應該從混亂到有序的這個歷史過程去研究(分析)分層架構,尤其是我們現在處在前後端分離的環境下,應用系統使用分層架構又面臨着什麼樣的劃分變化。

  • 第一個階段:應用系統只有兩層:表示(現)層和數據庫層。在視圖中直接使用數據庫所提供的訪問接口操作數據,如:JDBC,在視圖中直接使用ResultSet 表示數據。(需要特別注意的是:在視圖中直接使用 ResultSet 。)
  • 第二個階段:應用系統劃分爲三層:表現層、領域層和數據庫層。在這個階段,我們已經開始意識到模型了,模型的出現意味着在視圖中不在直接使用 ResultSet 了,而是使用從 ResultSet 相映射的編程語言中的結構體(struct)或者對象類(class)。這表示:從編程語言中的表示法可以抽象業務域中的概念結構了。
  • 第三個階段:應用系統劃分爲四層:表現層、應用(業務)邏輯層、領域層和數據庫層。由於業務邏輯依然存在視圖中,我們需要將視圖中的業務邏輯與視圖分離出來,此時出現了應用層。同時表現層也有所推進,表現層使用 MVC 架構。通過在 Controller 調用應用層所提供的接口並獲得接口所返回的模型(model)數據,並在 Controller 中將 model 和 view 組合起來,最終完成渲染工作。正是因爲在表現層使用 MVC 架構使得視圖(view)與下層實現松耦合。

應用系統使用分層架構在第三階段基本已經成熟。因爲我們要探討的是有關領域驅動設計(DDD)的分層架構,所以我們依然需要做進一步補充。具體包括兩方面的補充:

  • 第四個階段:面向對象的發展與應用,這個階段對總的層次劃分沒有大的變化。具體的變化的是有關應用層與領域層的內容,更具體的來說是領域層的變化。面向對象的出現使得大家開始使用面向對象來設計領域模型。這表示:由屬性操作所表示的對象模型用來抽象業務域中的概念模型。同時這又表示應用(業務)邏輯層中的業務邏輯也將被對象領域模型所承擔,應用層只需要控制協調有關對象領域模型的相關邏輯。非常幸運的是,Eric 對這一現象中的更多細節做了非常系統性的闡述,最終形成《領域驅動設計》這本書。
  • 第五個階段:前後端分離後對分層架構的影響。在前後端分離的項目中,表現層被完全的從後端剝離出來,後端只需要提供接口數據,如:RESTful , gRPC , Thrift , GraphQL 協議的後端接口。此時後端還是不是四層架構呢?這確實伴隨着兩條發展路線:一條是服務於前端的後端模式(BFF)。另一條是基於聚合對象的接口模式。它們的區別在於 BFF 頻繁變化,後者不會因爲前端頻繁變化而變化。

開源電商

Mallfoundry 是一個完全開源的使用 Spring Boot 開發的多商戶電商平臺。它可以嵌入到已有的 Java 程序中,或者作爲服務器、集羣、雲中的服務運行。

  • 領域模型採用領域驅動設計(DDD)、接口化以及面向對象設計。

項目地址:https://gitee.com/mallfoundry/mallfoundry

  • 感覺不錯,給個 star 。

 

 

架構之魂:分離業務邏輯和技術細節

https://www.jianshu.com/p/c6d385b04d5e

 

 

 

 

一、目錄

  • 架構的常識
    1. 什麼是架構?
    2. 爲什麼需要架構?
    3. 架構師的職責

  • 軟件架構

  • 軟件架構分類

  • 典型應用架構
    1. 分層架構
    2. CQRS
    3. 六邊形架構
    4. 洋蔥圈架構

  • COLA 應用架構
    1. 分層設計
    2. 擴展設計
    3. 規範設計
    4. COLA 架構總覽

  • 應用架構的核心


二、架構的常識

1. 什麼是架構?

關於架構這個概念很難給出一個明確的定義,也沒有一個標準的定義。

系統構架是對已確定的需求的技術實現構架、作好規劃,運用成套、完整的工具,在規劃的步驟下去完成任務。抽象來說,它是計算機系統結構,或稱計算機體系結構,是一個系統在其所處環境中最高層次的概念。

架構始於建築,是因爲人類發展(原始人自給自足住在樹上,也就不需要架構),分工協作的需要,將目標系統按某個原則進行切分,切分的原則,是要便於不同的角色進行並行工作。

2. 爲什麼需要架構?

有系統的地方就需要架構,大到航空飛機,小到一個電商系統裏面的一個功能組件都需要設計和架構。

與之相對應的,現在很多敏捷思想提倡 no design,只要 work 就好。期待好的架構可以在迭代中自然湧現。這個想法有點太理想化了,在現實中,只要能 work 的代碼,工程師是很少有動力去重構和優化的。

3. 架構師的職責

作爲架構師,我們最重要的價值應該是“化繁爲簡”。但凡讓事情變得更復雜,讓系統變得更晦澀難懂的架構都是值得商榷的。

架構師的工作就是要努力訓練自己的思維,用它去理解複雜的系統,通過合理的分解和抽象,使哪些系統不再那麼難懂 。我們應該努力構建易懂的架構,使得在系統上工作的其他人員(例如設計者、實現者、操作員等)可以較爲容易地理解這個系統。

三、軟件架構

軟件架構是一個系統的草圖。軟件架構描述的對象是直接構成系統的抽象組件。各個組件之間的連接則明確和相對細緻地描述組件之間的通信。在實現階段,這些抽象組件被細化爲實際的組件,比如具體某個類或者對象。在面向對象領域中,組件之間的連接通常用接口來實現。

軟件架構爲軟件系統提供了一個結構、行爲和屬性的高級抽象 ,由構件的描述、構件的相互作用、指導構件集成的模式以及這些模式的約束組成。軟件架構不僅顯示了軟件需求和軟件結構之間的對應關係,而且指定了整個軟件系統的組織和拓撲結構,提供了一些設計決策的基本原理。

軟件架構的核心價值應該只圍繞一個核心命題:控制複雜性。他並不意味着某個特定的分層結構,某個特定的方法論(貧血、DDD 等)。

四、 軟件架構分類

在介紹應用架構之前,我們先來看一下軟件架構的分類。

隨着互聯網的發展,現在的系統要支撐數億人同時在線購物、通信、娛樂的需要,相應的軟件體系結構也變得越來越複雜。軟件架構的含義也變得更加寬泛,我們不能簡單地用一個軟件架構來指代所有的軟件架構工作。按照我個人理解,將軟件架構劃分爲:

 

 
 

 

4.1 業務架構

由業務架構師負責,也可以稱爲業務領域專家、行業專家。業務架構屬於頂層設計,其對業務的定義和劃分會影響組織結構和技術架構。例如,阿里巴巴在沒有中臺部門之前,每個業務部門的技術架構都是煙囪式的,淘寶、天貓、飛豬、1688 等各有一套體系結構。而後,成立了共享平臺事業部,打通了賬號、商品、訂單等體系,讓商業基礎實施的複用成爲可能。

4.2應用架構

由應用架構師負責,他需要根據業務場景的需要,設計應用的層次結構,制定應用規範、定義接口和數據交互協議等。並儘量將應用的複雜度控制在一個可以接受的水平,從而在快速的支撐業務發展的同時,在保證系統的可用性和可維護性的同時,確保應用滿足非功能屬性要求(性能、安全、穩定性等)。

4.3分佈式系統架構

分佈式系統基本是稍具規模業務的必選項。它需要解決服務器負載,分佈式服務的註冊和發現,消息系統,緩存系統,分佈式數據庫等問題,同時架構師要在 CAP(Consistency,Availability,Partition tolerance)之間進行權衡。

4.4數據架構

對於規模大一些的公司,數據治理是一個很重要的課題。如何對數據收集、數據處理提供統一的服務和標準,是數據架構需要關注的問題。其目的就是統一數據定義規範,標準化數據表達,形成有效易維護的數據資產,搭建統一的大數據處理平臺,形成數據使用閉環。

4.5物理架構

物理架構關注軟件元件是如何放到硬件上的,包括機房搭建、網絡拓撲結構,網絡分流器、代理服務器、Web 服務器、應用服務器、報表服務器、整合服務器、存儲服務器和主機等。

4.6運維架構

負責運維繫統的規劃、選型、部署上線,建立規範化的運維體系。

五、典型應用架構

5.1. 分層架構

分層是一種常見的根據系統中的角色(職責拆分)和組織代碼單元的常規實踐。常見的分層結構如下圖所示:

 

 

5.2. CQRS

CQS(Command Query Separation,命令查詢分離),最早來自於 Betrand Meyer(Eiffel 語言之父,OCP 提出者)提出的概念。其基本思想在於,任何一個對象的方法可以分爲兩大類:

  • 命令 (Command): 不返回任何結果(void),但會改變對象的狀態。

  • 查詢 (Query): 返回結果,但是不會改變對象的狀態,對系統沒有副作用。

 

 

5.3. 六邊形架構

六邊形架構是 Alistair Cockburn 在 2005 年提出,解決了傳統的分層架構所帶來的問題,實際上它也是一種分層架構,只不過不是上下,而是變成了內部和外部(如下圖所示)。

 

 

六邊形架構又稱爲端口-適配器架構,這個名字更容器理解。六邊形架構將系統分爲內部(內部六邊形)和外部,內部代表了應用的業務邏輯,外部代表應用的驅動邏輯、基礎設施或其他應用。

適配器分爲兩種類型(如下圖所示),左側代表 UI 的適配器被稱爲主動適配器 (Driving Adapters),因爲是它們發起了對應用的一些操作。而右側表示和後端工具鏈接的適配器,被稱爲被動適配器 (Driven Adapters),因爲它們只會對主適配器的操作作出響應。

 

 

5.4. 洋蔥圈架構

洋蔥架構與六邊形架構有着相同的思路,它們都通過編寫適配器代碼將應用核心從對基礎設施的關注中解放出來,避免基礎設施代碼滲透到應用核心之中。這樣應用使用的工具和傳達機制都可以輕鬆地替換,可以一定程度地避免技術、工具或者供應商鎖定。

不同的是洋蔥架構還告訴我們,企業應用中存在着不止兩個層次,它在業務邏輯中加入了一些在領域驅動設計的過程中被識別出來的層次(Application,Domain Service,Domain model,Infrastructure 等)。

另外,它還有着脫離真實基礎設施和傳達機制應用仍然可以運行的便利,這樣可以使用 mock 代替它們方便測試。

 
洋蔥圈架構

在洋蔥架構中,明確規定了依賴的方向:

  • 外層依賴內層
  • 內層對外層無感知

六、COLA 應用架構

COLA 架構是阿里自主研發的應用架構,目前已經開源。在 COLA 的設計中,充分汲取了經典架構的優秀思想。除此之外,補充了規範設計和擴展設計,並且使用 Archetype 的方式,將架構固化下來,以便可以快速的在開發中使用。

COLA 開源地址:https://github.com/alibaba/COLA

6.1. 分層設計

COLA 的分層是一種改良了的三層架構。主要是將傳統的業務邏輯層拆分成應用層、領域層和基礎實施層。如下圖所示,左邊是傳統的分層架構,右邊是 COLA 的分層架構。

 

 

 

其每一層的作用範圍和含義如下:

1)展現層(Presentation Layer)

負責以 Rest 的格式接受 Web 請求,然後將請求路由給 Application 層執行,並返回視圖模型(View Model),其載體通常是 DTO(Data Transfer Object)。

2)應用層(Application Layer)

主要負責獲取輸入,組裝上下文,做輸入校驗,調用領域層做業務處理,如果需要的話,發送消息通知。當然,層次是開放的,若有需要,應用層也可以直接訪問基礎實施層。

3)領域層(Domain Layer)

主要是封裝了核心業務邏輯,並通過領域服務(Domain Service)和領域對象(Entities)的函數對外部提供業務邏輯的計算和處理.

4)基礎實施層(Infrastructure Layer)

主要包含 Tunnel(數據通道)、Config 和 Common。這裏我們使用 Tunnel 概念來對所有的數據來源進行抽象,這些數據來源可以是數據庫(MySQL,NoSql)、搜索引擎、文件系統、也可以是 SOA 服務等;Config 負責應用的配置;Common 是通用的工具類。

6.2. 擴展設計

對於只有一個業務的簡單場景,對擴展性的要求並不突出,這也是爲什麼擴展設計常被忽略的原因,因爲我們大部分的系統都是從單一業務開始的。但是隨着業務場景越來越複雜,代碼裏面開始出現大量的 if-else 邏輯。此時除了常規的策略模式以外,我們可以考慮在架構層面提供統一的擴展解決方案。

在擴展設計中,我們提煉出兩個重要的概念,一個是業務身份 ,另一個是擴展點 。

業務身份是指業務在系統唯一標識一個業務或者一個場景的標誌 。在具體實現中,我們使用 BizCode 來表示業務身份,其中 BizCode 採用類似 Java 包名命名空間的方式。例如,我們可以用 “ali.tmall” 表示阿里天貓業務,用 “ali.tmall.car” 表示阿里天貓的汽車業務,而用 'ali.tmall.car.aftermarket' 代表這是阿里天貓的汽車業務的後市場場景。

每個業務或者場景都可以實現一個或多個擴展點(ExtensionPoint) ,也就是說一個業務身份加上一個擴展點,可以唯一地確定一個擴展實現(Extension)。而這個業務身份和擴展點的組合,我們將其稱之爲擴展座標(ExtensionCoordinate),如下圖所示。

 

 
 

 

這樣,通過業務身份+擴展點,我們就可以從框架層面實現對不同租戶,不同業務,不同場景的擴展定製了。整個阿里業務中臺正是基於這個思想,實現的多業務支撐的。

6.3. 規範設計

任何事物都是規則性和隨機性的組合。規範的意義就在於我們可以將規則性的東西固化下來,儘量減少隨心所欲帶來的複雜度,一致性可以降低系統複雜度。從命名到架構皆是如此,而架構本身就是一種規範和約束,破壞這個約束,也就破壞了架構。

COLA 制定了一些列的規範:包括組件(Module)結構、包(Package)結構、命名等。

比如對於組件,我們要求使用 COLA 的應用都應該遵循如下圖所示的組件劃分:

 

 
 

 

6.4. COLA 架構總覽

在架構思想上,COLA 主張像六邊形架構那樣,使用端口-適配器去解耦技術細節;主張像洋蔥圈架構那樣,以領域爲核心,並通過依賴倒置反轉領域層的依賴方向。最終形成如下圖所示的組件關係。

 

 
 

 

換一個視角,從 COLA 應用處理響應一個請求的過程來看。COLA 使用了 CQRS 來分離命令和查詢的職責,使用擴展點和元數據來提升應用的擴展性。整個處理流程如下圖所示:

 

 
 

 

七、應用架構的核心

縱觀上面介紹的所有應用架構,我們可以發現一個共同點,就是“核心業務邏輯和技術細節分離 ”。

 

 
 

 

是的,六邊形架構、洋蔥圈架構、以及 COLA 架構的核心職責就是要做核心業務邏輯和技術細節的分離和解耦。

試想一下,業務邏輯和技術細節糅雜在一起的情況,所有的代碼都寫在 ServiceImpl 裏面,前幾行代碼是做 validation 的事,接下來幾行是做 convert 的事,然後是幾行業務處理邏輯的代碼,穿插着,我們需要通過 RPC 或者 DAO 獲取更多的數據,拿到數據後,又是幾行 convert 的代碼,在接上一段業務邏輯代碼,然後還要落庫,發消息.....等等。

再簡單的業務,按照上面這種寫代碼的方式,都會變得複雜,難維護。

因此,我認爲應用架構的核心使命就是要分離業務邏輯和技術細節。讓核心業務邏輯可以反映領域模型和領域應用,可以複用,可以很容易被看懂。讓技術細節在輔助實現業務功能的同時,可以被替換。



作者:梅西愛騎車
鏈接:https://www.jianshu.com/p/c6d385b04d5e
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章