Sunday, May 2, 2021

[Domain-Driven Design] DDD 學習路徑與資源分享

Learning Roadmap


https://ithelp.ithome.com.tw/articles/10216792

 

[Domain-Driven Design] 向 Anemic Model 說不

 開始前想先跟大家介紹一個有名的反模式: 貧血模型 (Anemic Model),這個反模式泛指那些只有 getter 與 setter 的 model 。這些 model 缺乏行為能力,導致使用者每次都要自己組合出自己要的功能。

因此貧血模型看似什麼都可以透過資料設定去做到,但因為沒有具有行為敘述的 method function ,所以難以應用於複雜的操作中。總體而言能力十分受限,就像貧血一樣。
貧血模型用起來像在教小孩子一樣,一個指令一個動作還很容易忘掉 ;具有行為能力的模型則像跟大人溝通一樣,一次行動就能完成許多指令。
沒有行為能力的程式模型,就像這段組合鍵的程式碼一樣:
=================================================
Role person  = new Person();
// dragon fist starts ~~
person.up();
person.down();
person.left();
person.right();
person.press('A');
person.press('B');// dragon fist ends ~~
=================================================
但當我們了解業務邏輯後,就可以將這段程式封裝成有行為能力的 function:
=================================================
Role person = new Person();
person.dragonFist();
=================================================
這樣的優勢非常明顯,一來程式易懂好維護,二來要修改也很簡單。重點是程式碼從組合碎片式的資訊轉而關注程式的行為能力
這時可能就會有人有疑問...「封裝的好處我懂,但如果濫用了程式碼一樣會亂啊!而且只是把程式封裝為什麼需要 DDD?」
配合業務語言封裝程式的行為
DDD 注重將業務語言注入程式模型之中,所以只會對重點業務行為進行封裝。如此一來,與其隨意封裝程式碼, DDD 將程式模型與業務邏輯綁在一起,不但可以緊隨業務的變化做修改,而且利用業務語言做封裝也解決了兩大程式難題之一:命名。
大家可以嘗試看看用業務行為為程式碼命名。最常見就是將原先 CRUD 的貧血命名法更改為充滿業務含義的命名方式。
比如說一個 user 的 CRUD 操作可能就變成 register, getProfile, getActivityHistory, updateProfile, changePassword, deactivateAccount, deleteAccount 等等。
這種做法會在跨模型的情境下發揮更大的優勢,舉個咖啡廳的例子,假如一個正常流程包括點餐、製作、送餐,可以寫出以下程式碼:
=================================================
customer = new Customer('Bill');
order = Order.create(customer, 'Coffee');
staff = new Staff(9527);
cashier = new Cashier();
// 結帳
order.setStaff(staff);
staff.setCashier(cashier);
staff.setOrders(order);
cashier.addOrder(order);

// 泡咖啡
cup = new Cup();
staff.setCup();
cup.setFilterCone(new FilterCone());
cup.setCoffeeGround(new Coffee());
staff.brew(cup);
staff.wait();
staff.setFilterCone(null);
// 送餐
staff.setCoffeeTo(customer);
customer.setCoffee(order)
=================================================

以上的程式碼可以明顯看出幾個問題:

  • 所有屬性都可異動
  • 難讀、業務意圖不明顯
  • 難以應付未來的修改
導入 DDD 並與領域專家不斷溝通形成 Ubiquitous Language 後,讓我們修改一下程式碼:
=================================================
barista = new Barista(9527);
customer = new Customer('Bill');
order = customer.placeOrder(order);
barista.processPayment(order);
barista.make(order);
barista.serveOrderTo(order, customer);
=================================================
修改後可以發現,程式的行為都十分貼近現時使用情境,讓即使不會寫程式碼的人都可以看懂了!

總結: DDD 的優缺點

使用 DDD 有以下優點:

  1. 促進跨團隊的溝通、理解領域知識。
  2. 專注在核心業務上
  3. 保護業務邏輯,不會因技術細節 (如 db 、框架、基礎設施)而影響。
  4. 開發時更靈活彈性、重用程式更方便,能夠面對未來的變化與成長。
  5. 更好的模組化 = 更容易測試 (完美搭配 TDD)。
  6. 出現 Bug 時更快找到原因 (已經將關注點分離,查出哪邊出問題很快)。
  7. 有利用拆分與設計 microservice (這也是最近幾年紅的原因)

不過也有以下幾點需注意:

  1. 較難快速建立產品 (戰術實作部分)
  2. 沒有領域專家會很難開頭 (新創需注意)
  3. 要導入溝通文化、學習成本高
  1. 對於高度科技(數學)專業的專案不一定合適

n8n index

 【n8n免費本地端部署】Windows版|程式安裝x指令大補帖  【一鍵安裝 n8n】圖文教學,獲得無限額度自動化工具&限時免費升級企業版功能