領域驅動設計

領域驅動設計(英語:domain-driven design,縮寫 DDD)是軟件程式碼的結構及語言(類別名稱、類別方法、類別變數)需符合業務領域英語business domain中的習慣用法。例如處理租賃業務的軟件,其型別可以命名為LoanApplication及Customer,其方法可以用AcceptOffer及Withdraw。

領域驅動設計可以將實現對應到持續進化的模型[1]

領域驅動設計的前提是:

  • 把專案的主要重點放在核心領域(core domain)和領域邏輯
  • 以領域中的模型為基礎,進行複雜的設計
  • 讓技術人員以及領域專家英語Subject-matter expert合作,以迭代方式來完善特定領域問題的概念模型

該詞是由埃里克・埃文斯(Eric Evans)在其同名書中創造。[2]

概念

編輯

模型中有以下概念:

上下文(Context)
情境、脈絡、上下文。比如:電子商務系統。
領域(Domain)
知識,影響,或活動。客戶使用軟件要處理旳問題種類即為軟件的領域。
模型(Model)
一類描述域的不同方面並可用於解決相關問題的系統化的抽象。
通用語言(Ubiquitous Language)
一種領域專家使用,為了描述域模型而構造的語言,以減少溝通成本。


戰略

編輯

理想情況下,只有一個統一的模型。 但是通常情況下都無法實現,因此在實踐中通常分成多個模型。 認識這個事實並遵守它對實踐是非常有益的。 策略設計的目的是設計一套原則用於是維護模型完整性,提升領域模型和使用多個模型。

界限上下文(bounded context)

編輯

任何大型專案都有多個模型。 然而,當基於不同模型的代碼相結合,軟件變得越來越多,不可靠,並且難以理解。 團隊成員之間的交流變得越來越難。 模型的使用情境變得越來越不清晰。

因此:需要明確定義模型適用的上下文,並且根據團隊組織,應用程式特定部分的使用情況以及代碼庫和資料庫模式等物理表現明確設置邊界。 保持模型在這些範圍內嚴格一致,並且不被外部的問題影響。

持續整合(continuous integration)

編輯

當愈多人在相同的有限背景下工作時,模型就愈應該分裂。 團隊越大,問題就越大,即使只有三四個人也會遇到嚴重的問題。 然而,將系統分解為更小的環境最終會失去一個有價值的整合和一致性。

因此:建立一個經常合併所有代碼和其他實現工件的過程,用自動化測試快速標記碎片。通過持續地運用統一術語去夯實隨着概念在不同人的頭腦中的演變而逐漸形成對模型的共同觀點。

上下文對映(context map)

編輯

在缺乏全域認識的情況下,個別有界上下文會留下一些問題。 其他模型的背景可能仍然是模糊不清的。 其他團隊的人不會意識到上下文的界限,並且會不知不覺地做出模糊邊緣或使連接複雜化的變化。 當連接必須在不同的上下文之間進行時,它們往往會相互滲透。

因此:確定專案中正在使用的每個模型並定義其有界的上下文。 這包括非物件導向子系統的隱式模型。 命名每個有界的上下文,並將其命名為通用語言的一部分。 描述模型之間的關聯點,確保任何用於共用交流的詞語都有清晰明確的含義。 對映現有的情形。

基礎

編輯

領域驅動設計一書中[2]闡述了一些高層次的概念和實踐,比如通用語言,這意味着領域模型應該形成領域專家為描述系統需求而提供的共同語言,同樣的,這些語言也需要能夠被商業用戶或贊助商和軟件開發商使用。本書專注於將領域層描述為具有多層體系結構的物件導向系統中的常見層次之一。在 DDD 中,有表示,建立和檢索域模型的工件:

Entity
一個不由自身屬性定義而是由標識線和它的身份定義的對象
例如:大多數航空公司在每次航班上都獨特地區分每個座位。每個席位都是在這種情況下的一個實體。不過,西南航空,EasyJet 和瑞安航空並沒有區分每個座位;所有的座位都是一樣的。在這種情況下,一個席位實際上是一個Value Object
Value Object
只包含元素屬性的不可變對象
例如:當人們交換名片時,他們一般不會區分每張獨特的名片;他們只關心印在卡片上的資訊。在這種情況下,名片是 Value Object
Service
強調與其他對象的關係,只定義了可以為客戶做什麼,不應該替代 Entity 和 Value Object 的所有行為
Module
一種表達機制,劃分代碼和概念
Factory
對於那些需要建立特定域對象的方法應該委派給工廠對象,因為這樣可以更容易的替換實現
Repository
對於檢索特定域對象的方法應該委派給 Repository 對象,因為這樣可以很容易地互換替代儲存的實現
Aggregate
由 ROOT ENTITY 繫結在一起的對象的集合,也稱為聚合根。聚合根通過禁止外部對象保持對其成員的參照來保證在聚合內進行的更改的一致性
例如:駕駛汽車時,不必思考如何讓車輪前進,如何點燃引擎等。你只需要正常的使用。在這種情況下,汽車是其他幾個對象的集合,並作為所有其他系統的聚合根
Domain Event
一個域對象定義了一個事件。域事件是域專家所關心的事件

局限

編輯

為了幫助保證模型能作為一個單純並有用的語言結構,團隊通常必須在領域模型中實現大量的隔離和封裝。因此,基於領域驅動設計的系統可能會花費相對較高的成本。雖然域驅動設計提供了許多技術優勢,如可維護性,但 Microsoft 建議僅將它應用於複雜領域中,在這些複雜領域中,通過模型和語言處理能夠在複雜資訊中提供交流便利性的,並且能夠該領域達成共識。[3]

與其它概念的關係

編輯

工具

編輯

採用 DDD 並不依賴於特定的工具。然而,也有許多開源的工具和框架可用,包括:

參見

編輯

參考文獻

編輯
  1. ^ Domain driven design, [2017-11-03], (原始內容存檔於2021-04-12) .
  2. ^ 2.0 2.1 Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley. 2004 [August 12, 2012]. ISBN 978-032-112521-7. (原始內容存檔於2019-05-13). .
  3. ^ Microsoft Application Architecture Guide, 2nd Edition, [2017-12-25], (原始內容存檔於2019-01-30) 

外部連結

編輯