###### tags: `領域驅動開發` `DDD` `Domain Driven Design` # DDD實戰-簡易整理 ### 一、回顧 (DDD) 重點在於協助您在使用案例相關的商務實際情況下建立模型,然後根據Domain定義後續不同的Context與彼此的對應關係,再與事件驅動方式實際實現。 書中所提例子 : 電商系統,人員瀏覽商並下訂後交易。 - 定義Domain - 根據問題空間與解決方法定義出Domain - Core Domain :產品最有價值部分 (Ex AI 推薦購買商品需求) - Supporting Subdomain : 未提供核心競爭力,但支援核心所需功能 (Ex 購物需求) - Generic Subdomain : 未提供核心競爭力,但整個系統都可能會用到它 (Ex 身份認證需求、金流串接) ![](https://i.imgur.com/Mdmf3qn.png) ![](https://i.imgur.com/H1uYlZQ.png) - 根據語意(Linguistic)與業務能力(Business Capability)定義BoundContext - 重點一、通常識別 Bounded Context 會由兩點下手:語意(Linguistic)與業務能力(Business Capability)。 - 電商例子(語意-業務能力) - 登入-帳號管理 => 身分管理Context (Identity) - 商品-商品選擇 => 商品目錄Context (Catalog) - 下購-購買功能 => 選購Context (Purchase) - 重點二、注重業務能力勝過資料分類 (習慣性地用資料表去起始設計系統,甚至把業務邏輯與 ORM 框架綁在一起。這麼一來容易造成物件乘載太多的責任,比如說「顧客」是屬於「會員管理系統」還是屬於「購物系統」?) - Context定義出後,根據幾種方法(設計模式,或撰寫程式技巧)去做Context Mapping - Shared Kernel - Partnership - Anti-corruption Layer - Open Host Service/Published Language - Separate Way - Big Ball of Mud - Customer-Supplier - Conformist ![](https://i.imgur.com/Nr2dQiP.png) - 使用或設計軟體架構最小化建置與維護「需求系統」所需要的人力資源。 - 軟體的架構與功能需求沒有關係 - 軟體架構是非功性需球 Non-Funcitonal Requirement (系統達成的任務的能力) - 常見軟體架構大概有這些類型: - MVC - MVP - Layered Architecture - Client Server - Microservice - Event-Driven Architecture - Pipe-Filter - MVVM - DDD 不等於 Clean Architecture,兩者關注的面向不同。DDD 的主要目的是將軟體的模型更貼近業務需求,架構只是為了達到目的的工具。 ![](https://i.imgur.com/jNqfWG2.png) --- ### 二、何謂Entity,如何定義他 根據電商前面例子, 身分管理、 商品目錄與選購中,你覺得什麼是Entity? 顧客、訂單、商品等等。這些物件不被他們的屬性所辨識(比如年齡、金額),而是由一個專屬的身份標誌 (Identity)來辨識。這種時候,我們就需要 Entity 的幫助讓我們在不同的物件中找到我們要的那一個。 Entity 最大的特徵就是有 Identity 的概念,所以常會搭配一個擁有唯一值的 ID 欄位。但這邊要澄清一個誤解,不是有 ID 就是 Entity,重點是你在不在乎他生命週期的變化。 Entity具有幾個特徵 - 具有唯一值ID - 具有狀態 - 生命週期有可能無限長 - 一個 Entity 是可變的、長壽的,所以通常會有複雜的生命週期變化,如一套 CRUD 的操作 - 不只會實作資料屬性,還會實作具有相關領域邏輯的作業或方法 實體代表領域物件,而且主要是由其身分識別、連續性及一段時間的持續性所定義,而不只是由包含這些項目的屬性所定義。 如同 Eric Evans 說,「主要由其身分識別定義的物件稱為「實體」(Entity)。 實體在領域模型中很重要,因為它們是模型的基礎。 已Order訂單為例子 - 訂單ID - 訂單屬性(ID,Name,Address) - 訂單操作Method(EditName, EditAddress) ![](https://i.imgur.com/0mILDKG.png) ### 三、跟ValueObject有何不同 - 當一個物件沒有概念上的標識 (conceptual identity),而你只關心它的屬性時,這個物件就可以建立成 Value Object。 - Value Object 的屬性都是為了要描述某一個事物的特徵。 - 判斷這兩者的標準就在於系統在不在乎這個物件的生命週期變化。 ![](https://i.imgur.com/9t7qZbL.png) ![](https://i.imgur.com/7GmX3oZ.png) ### 四、如何產出 Entity Id? **1. 來自用戶的輸入** 這是一個非常直接的做法,比如使用用戶的 email 或是身分證字號等等作為 ID,但也容易造成額外的成本。最大的成本就在於,你需要由用戶負責產生符合需求的身份認證資料非常困難。此時的 ID 可能是唯一的,但卻有可能是不正確的。 甚至,身分證字號也有重複的可能性。 因此,我們可以將用戶輸入的資料作為 Entity 的屬性。這些屬性可以用來做搜尋用,但大多時候並不適合作為 Entity 的 ID。 **2. 使用持久化機制來產生** 最常見的就是使用資料庫自動生成 ID,最常見的就是 SQL 對 ID 下 AUTO_INCREMENT 讓 ID 的值自動遞增。又或者也可以向資料庫索取一個 UUID (或 GUID) 作為 ID 的值。 這樣的做法好處是可以減少程式的複雜性,直接把產生的工作交給持久化機制處理。但也容易招致效能問題的疑慮(UUID/GUID 的產生)。而且當你無法從程式碼找出 ID 的生產機制時,也會增加程式碼的隱含性不利於閱讀。 另外,使用持久化機制時,也需要特別考量這個 ID 的生成應該要在該物件持久化 (ie 存入資料庫) 之前或是之後,以配合程式的需求。 註:這裡會使用「持久化」一詞是因為儲存資料的方式不止資料庫一種,故用更通稱的方式描述。 **3. 在程式中產生** 在程式中產生 ID 是最常見的方法之一,這種方法好處是可以更容易掌握生產的時機,此外,更可以客製化你的 ID 格式,比如一筆訂單你可以用 order-20190930-c764e787-8182 作為 ID,如此一來,在 debug 時就不用被一堆天文數字般的 ID 搞得昏頭脹腦。所以以個人經驗來說,即使增加了一點複雜度,會最推薦這個方式。 **4. 由另一個 Bounded Context 提供** 最複雜的一種就是來自於另一個 Bounded Context 提供的 ID。這種可能出現在當你需要調用 API 的時候,得到對方的資料後存取下來。這種方式的複雜點在於,你不只要考慮本地端的 Entity,也需要考慮外部 Bounded Context 的改變情況,雖然可以透過訂閱另一個 Bounded Context 的方式做到,但仍舊十分麻煩。 ### 五、.NET Core 實作微服務領域模型 ![](https://i.imgur.com/itacz1m.png) ![](https://i.imgur.com/AWFlSfi.png) 參考 : https://ithelp.ithome.com.tw/articles/10223150 https://docs.microsoft.com/zh-tw/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/microservice-domain-model https://docs.microsoft.com/zh-tw/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/ddd-oriented-microservice
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up