領域驅動設計(DDD)

【注】本文譯自:
https://www.geeksforgeeks.org/domain-driven-design-ddd/

領域驅動設計(Domain-Driven Design)是程序員?Eric Evans?于 2004 在他的《 領域驅動設計:解決軟件核心中的復雜性》一書中提出的一個概念。
這是一種自頂向下的軟件設計方法。首先,讓我們嘗試重點介紹一下在這種情況下領域的含義。
什么是領域?
在軟件開發(fā)的上下文中,“域”指的是業(yè)務。在應用程序開發(fā)過程中,通常使用術語域邏輯或業(yè)務邏輯?;旧?,業(yè)務邏輯是應用程序邏輯所圍繞的知識領域。 應用程序的業(yè)務邏輯是一組規(guī)則和指導原則,用于解釋業(yè)務對象應如何相互交互以處理建模數據。
注意:
軟件工程領域的領域是要在其上構建應用程序的業(yè)務。
領域驅動設計:
假設我們的軟件已經使用了所有最新技術堆棧和基礎設施,這樣的軟件設計架構非常棒,但是當我們在市場上發(fā)布這個軟件時,最終還是要由最終用戶來決定我們的系統(tǒng)是否優(yōu)秀。另外,如果系統(tǒng)不能解決業(yè)務需求,對任何人都沒有用處;不管它看起來有多漂亮,或者它的基礎設施有多好。根據?Eric Evans?的說法,當我們在開發(fā)軟件時,我們的重點不應該主要放在技術上,而應該主要放在業(yè)務上。記?。?/p>
“客戶的工作不是知道他們想要什么“---史蒂夫·喬布斯
領域驅動設計涉及兩種設計工具,一種是戰(zhàn)略設計工具,另一種是戰(zhàn)術設計工具。程序員或開發(fā)人員通常處理戰(zhàn)術設計工具,但如果我們有戰(zhàn)略設計工具的知識和良好的理解,它將幫助我們構建好的軟件。
Spring 數據家族下的大多數框架都是根據領域驅動的設計方法構建的。
戰(zhàn)略設計:
戰(zhàn)略設計工具幫助我們解決所有與軟件建模相關的問題。它是一種類似于面向對象設計的設計方法,在面向對象設計中,我們被迫從對象的角度思考問題。在戰(zhàn)略設計方面,我們被迫從環(huán)境的角度來思考。
上下文(Context):
我們可以把這個詞看作是一個英語單詞,它指的是某一事件、事件、陳述或想法的情況,它的意思可以根據這些情況來確定。
除了上下文之外,戰(zhàn)略設計還討論了模型、泛在語言和邊界語境。這些是領域驅動設計的戰(zhàn)略設計中常用的術語。讓我們逐一理解。
模型:充當核心邏輯并描述領域的選定方面。它用于解決與該業(yè)務有關的問題。
通用語言:所有團隊成員使用的一種公共語言,用于連接團隊圍繞領域模型的所有活動。與領域專家和團隊成員交談時,可以將其視為對類、方法、服務和對象使用通用動詞和名詞。
邊界上下文:指的是上下文的邊界條件。它是對邊界的描述,并充當一個閾值,在這個閾值中定義并適用于特定的域模型。
戰(zhàn)術設計:
戰(zhàn)術設計討論實現(xiàn)細節(jié),即建模領域。它通常會處理有界上下文中的組件。我們可能聽說過或使用過諸如服務、實體、存儲庫和工廠之類的東西。它們都是通過域驅動設計創(chuàng)造并流行的。戰(zhàn)術設計過程發(fā)生在產品開發(fā)階段。
讓我們討論一些重要的戰(zhàn)術設計工具。 這些工具是高級概念,可用于創(chuàng)建和修改域模型。
1. 實體:
面向對象原則工作的程序員可能知道類和對象的概念。在這里,實體是具有某些屬性的類。這些類的實例具有全局標識,并且在整個生命周期中都保持相同的標識。請記住,屬性狀態(tài)可能會發(fā)生變化,但身份永遠不會改變。簡而言之,實體可以實現(xiàn)一些業(yè)務邏輯,并且可以使用 ID 進行唯一標識。在編程的上下文中,它通常在 DB 中作為行持久保存,并且由值對象組成。
2. 值對象:
不可變的輕量級對象,沒有任何標識。值對象通過執(zhí)行復雜的計算,將繁重的計算邏輯與實體隔離開來,從而降低了復雜性。

在上圖中,User?是一個實體,Address?是一個值對象,地址可以更改很多次,但用戶的身份證號永遠不會更改。每當地址更改時,都會實例化一個新地址并將其分配給用戶。
3. 服務:
服務是無狀態(tài)的類,可以適合實體或值對象以外的其他地方。簡而言之,服務是一種功能,存在于實體和值對象之間的某個位置,但它既不與實體相關,也不與值對象相關。
4. 聚合:
當我們有更大的項目時,對象圖也變得更大,更大的對象圖更難維護。聚合是位于單個事務邊界下的實體和值的集合。基本上是聚合,控制變化,有一個根實體叫做聚合根。根實體以聚合的方式管理其他實體的生命周期。

在上面的示例中,如果根實體?User?或?Order?被刪除,則與該根實體關聯(lián)的其他實體將毫無用處,并且該關聯(lián)的信息也將被刪除。這意味著聚合在本質上總是一致的,這是在域事件的幫助下完成的。生成域事件是為了確保最終的一致性。
在上面的例子中,如果用戶的地址已經改變,那么它必須同樣反映在訂單上。為此,我們可以觸發(fā)一個從 User 到 Order 的域事件,以便 Order 更新地址,這樣我們就有了最終的一致性,Order 也將最終一致。
聚合和聚合根的其他例子可以是對帖子的評論、問答細節(jié)、銀行事務細節(jié)等。ORM 工具如?hibernate?在創(chuàng)建一對多或多對一關系時使用了大量聚合。
5. 工廠和存儲庫:
工廠和存儲庫用于處理聚合。工廠幫助管理聚合生命周期的開始,而存儲庫幫助管理聚合生命周期的中間和末端。工廠幫助創(chuàng)建聚合,而存儲庫幫助持久化聚合。我們應該總是為每個聚合根創(chuàng)建存儲庫,而不是為所有實體創(chuàng)建存儲庫。
工廠是 GoF 的設計模式,工廠是有用的,但在聚合規(guī)則的上下文中不是強制性的。
領域驅動設計的優(yōu)點:
提高了我們的技藝
提供了靈活性
更傾向于域而不是接口
通過通用語言減少了團隊之間的溝通差距
領域驅動設計的缺點:
需要一個具有很強領域專業(yè)知識的專業(yè)人員
鼓勵團隊遵循迭代實踐