寫給前端小姐姐的 DDD - 領域驅動設計

背景

DDD領域驅動設計,在後端領域,現在應用非常廣泛,在我看來,前端(特別是 React)也是非常適合DDD(小哥哥也可以看這篇文章)

什麼是DDD?

Domain Driven Design - 領域驅動設計

重點是這個:設計

在學習一個新的知識時候,我推薦用 80% 的時間去學習那些 20% 重要的內容  -  二八定律,Peter

領域驅動設計 (DDD) 是一種通過將實現連接到持續進化的模型來滿足複雜需求的軟件開發方法. 領域驅動設計的前提是:

把項目的主要重點放在覈心領域和領域邏輯上

把複雜的設計放在領域模型上

發起技術專家和領域專家之間的創造性協作, 以迭代方式完善解決特定領域問題的概念模型


理論學完了,是不是很懵逼?別急,上面的看不懂就假裝是我拿來湊字數的,你只要記住 DDD  = 領域驅動設計

DDD - 舉個例子

傳統的四層架構如圖所示:

分別爲:

User Interface 爲用戶界面層(或表示層),負責向用戶顯示信息和解釋用戶命令。這裏指的用戶可以是另一個計算機系統,不一定是使用用戶界面的人。

Application 爲應用層,定義軟件要完成的任務,並且指揮表達領域概念的對象來解決問題。這一層所負責的工作對業務來說意義重大,也是與其它系統的應用層進行交互的必要渠道。應用層要儘量簡單,不包含業務規則或者知識,而只爲下一層中的領域對象協調任務,分配工作,使它們互相協作。它沒有反映業務情況的狀態,但是卻可以具有另外一種狀態,爲用戶或程序顯示某個任務的進度。

Domain 爲領域層(或模型層),負責表達業務概念,業務狀態信息以及業務規則。儘管保存業務狀態的技術細節是由基礎設施層實現的,但是反映業務情況的狀態是由本層控制並且使用的。領域層是業務軟件的核心,領域模型位於這一層。

Infrastructure 層爲基礎實施層,向其他層提供通用的技術能力:爲應用層傳遞消息,爲領域層提供持久化機制,爲用戶界面層繪製屏幕組件,等等。基礎設施層還能夠通過架構框架來支持四個層次間的交互模式。

具體示例可以看下面我畫的這個圖:

這是以我司的產品舉例

User Interface 層:爲三個入口 APP PC 微信端

Application 爲應用層:財務系統 房源系統 合同系統等

Domain 領域層:用戶領域的service(接口)

Infrastructure 基礎實施層:用 mysql redis k8s 等

這樣是不是很清晰了?

這四個層,你應該能分清楚了。但是,這是基於後端的分析,我們現在開始,基於前端來一份舉例


前端 DDD?

還是這張圖

四層,對於前端進行拆分

我們這次,以掘金 PC 端產品舉例

進行四層拆分

這裏是做了一個簡單的模擬拆分,大家重點關注domain領域這層, 精髓在這。

爲什麼說我認爲 React 很適合 DDD 呢?

React 中,有 function component(函數組件) 和 react hooks(而且可自定義)

領域驅動設計,說白了,重點是優化設計,但是實現的重點在於領域。所以這個領域的拆分就很有靈性了

說到這裏可能有很多爭議,對於我寫的內容,沒關係,你不喜歡別看就行了。


拿用戶系統領域舉例

在用戶系統中,我們進入頁面後,又會劃分爲幾個模塊

例如:

個人信息、最近動態、個人成就等等,這個領域每個不同的模塊,像不像是我們前端的組件化?

可是大家別忘了,UI 跟邏輯是要分離的。

爲什麼要分離?因爲 UI 跟邏輯在前端,同樣需要複用。

在我們拆分完了領域後,會得到若干不同的領域

但是在拆分領域後,我們就可以開始梳理這個領域內的邏輯了

例如,通過用戶 ID 查詢用戶信息,查詢用戶的最近動態等

在用戶模塊,我們會用到通過用戶 ID 查詢用戶信息這個邏輯,但是在文章模塊(其他領域)同樣會用到

例如:在評論系統領域,也會用到通過 ID 查詢用戶信息的邏輯

那這個邏輯,就需要複用了。在 DDD 的世界裏,高內聚,低耦合的實現,最好是通過單純的接口調用。例如:

A 領域(評論系統)需要通過用戶 ID 去查詢用戶系統,不應該直接去查詢數據庫,而是去調用 B 領域(用戶系統)提供的純粹查詢接口.

那麼前端可以借鑑這個思路嗎?當然可以。

借鑑後端微服務思路 - 前端邏輯複用 - DDD

還是剛纔的例子:在評論系統領域,也會用到通過 ID 查詢用戶信息的邏輯

首先我們定義好不同的領域

分爲:user 和 comment 用戶、評論領域

定義好獲取用戶信息的自定義 hooks

import { useState, useEffect } from 'react';

export function UseUser({ user_id }) {
  const [useInfo, setUserInfo] = useState({});
  useEffect(() ={
    fetch('/get-user').then((res) ={
      setUserInfo(res.data);
    });
  }[user_id]);
  return useInfo;
}

那麼當評論領域需要用到的時候,只需要找到 user 領域提供的這個useUser,調用一次就可以通過 ID 獲取到用戶信息了。而開發評論領域的同事,就不需要關心這個接口怎麼實現的,是 post 還是 get 請求方式,接口地址是什麼。

UI 複用 - DDD

同理,如上

舉了例子,回到概念

當我們用前端項目和代碼實際舉例之後,再回到概念。

我個人認爲 DDD 最大的好處是:接觸到需求第一步就是考慮領域模型,而不是將其切割成數據和行爲,然後數據用數據庫實現,行爲使用服務實現,最後造成需求的首肢分離。DDD讓你首先考慮的是業務語言,而不是數據。重點不同導致編程世界觀不同。

這句話也是我在網上看到別人總結的,覺得很對。

既然是領域驅動設計,那麼我們主要的關注點理所當然應該放在如何設計領域模型上,以及對領域模型的劃分。

領域並不是多麼高深的概念,比如,一個保險公司的領域中包含了保險單、理賠和再保險等概念;一個電商網站的領域包含了產品名錄、訂單、發票、庫存和物流的概念。這裏,我主要講講對領域的劃分,即將一個大的領域劃分成若干個子域。


在日常開發中,我們通常會將一個大型的軟件系統拆分成若干個子系統。這種劃分有可能是基於架構方面的考慮,也有可能是基於基礎設施的。但是在 DDD 中,我們對系統的劃分是基於領域的,也即是基於業務的。

於是,問題也來了:首先,哪些概念應該建模在哪些子系統裏面?我們可能會發現一個領域概念建模在子系統 A 中是可以的,而建模在子系統 B 中似乎也合乎情理。第二個問題是,各個子系統之間的應該如何集成?有人可能會說,這不簡單得就像客戶端調用服務端那麼簡單嗎?問題在於,兩個系統之間的集成涉及到基礎設施和不同領域概念在兩個系統之間的翻譯,稍不注意,這些概念就會對我們精心創建好的領域模型造成污染。

如何解決?答案是:限界上下文和上下文映射圖。

在一個領域 / 子域中,我們會創建一個概念上的領域邊界,在這個邊界中,任何領域對象都只表示特定於該邊界內部的確切含義。這樣邊界便稱爲限界上下文。限界上下文和領域具有一對一的關係。

舉個例子,同樣是一本書,在出版階段和出售階段所表達的概念是不同的,出版階段我們主要關注的是出版日期,字數,出版社和印刷廠等概念,而在出售階段我們則主要關心價格,物流和發票等概念。我們應該怎麼辦呢,將所有這些概念放在單個 Book 對象中嗎?這不是 DDD 的做法,DDD 有限界上下文將這兩個不同的概念區分開來。

從物理上講,一個限界上下文最終可以是一個 DLL(.NET) 文件或者 JAR(Java) 文件,甚至可以是一個命名空間(比如 Java 的 package)中的所有對象。但是,技術本身並不應該用來界分限界上下文。

將一個限界上下文中的所有概念,包括名詞、動詞和形容詞全部集中在一起,我們便爲該限界上下文創建了一套通用語言。通用語言是一個團隊所有成員交流時所使用的語言,業務分析人員、編碼人員和測試人員都應該直接通過通用語言進行交流。

對於上文中提到的各個子域之間的集成問題,其實也是限界上下文之間的集成問題。在集成時,我們主要關心的是領域模型和集成手段之間的關係。比如需要與一個 REST 資源集成,你需要提供基礎設施(比如 Spring 中的 RestTemplate),但是這些設施並不是你核心領域模型的一部分,你應該怎麼辦呢?答案是防腐層,該層負責與外部服務提供方打交道,還負責將外部概念翻譯成自己的核心領域能夠理解的概念。當然,防腐層只是限界上下文之間衆多集成方式的一種,另外還有共享內核、開放主機服務等,具體細節請參考《實現領域驅動設計》原書。限界上下文之間的集成關係也可以理解爲是領域概念在不同上下文之間的映射關係,因此,限界上下文之間的集成也稱爲上下文映射圖。

這段話來源於: https://www.cnblogs.com/Leo_wl/p/3866629.html

DDD,不止適用於本文之前提到的四層架構,還有事件驅動架構,六邊形架構等。(其實要完全學精,要下一番功夫。)

例如:六邊形架構

所以,DDD 前端落地的前提:對業務足夠了解,在開發之前,召集所有的研發進行一次徹底的頭腦風暴,把領域和子域劃分清楚!想清楚再動手,抽離 UI 組件和邏輯(自定義 hooks),再把這些組裝成真正的頁面。

最後

DDD 並不是只適用於編程,在生活中同樣適用,例如不同的領域需要安排不同的人工作,當你需要做某件事的時候,不是自己去學習從零開始,而是去找專業的人做專業的事。- 這也是 DDD 的思想

DDD 目前在國外、後端領域非常火爆,但是在我們公司,前端重構也在使用 DDD,如果你感興趣,可以去買本相關的書籍,好好學習下,然後看是否能在前端項目中落地。

❤️ 謝謝支持


本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/BB-wADmzrUMbGlH_cyqJUQ