領域驅動開發
DDD
Domain Driven Design
在闡述Module前,讓我們先來比對非物件化設計與物件化設計的差異性。看到下圖左,在非物件化的傳統設計,資料與方法操作上是整個拆開設計,在資料流複雜外我們可以看相依性高,偶合的狀況也較高。
接著討論物件化設計部分,先不論封裝等物件操作技巧,單純根據資料與方法關係設計出物件(物件特性:資料(Data) 物件行為:方法(Function)),我們可以看到原本互相依賴的Fun關係可各自獨立使用,在資料流上也較為單純。
物件化後,雖然在資料操作面上簡化許多,但隨著專案功能性逐漸增加,物件與功能處理流程上會趨近越複雜,如下圖為一個簡易的系統,此系統根據外部Sensor系統獲取、過濾與計算資料,在沒模組化的設計前提,可以看到Control與Data Flow呈現一個較零散的關係狀態
此時我們根據Sensor功能額外設計一個Sensor模組如下,此時我們就可以針對Sensor相對應的資料模組將之封裝在模組內,此模組對外則就單純開放運算(calculation)與過濾(filtering)的功能。
模組化後可以明顯看出控制與資料流的彼此相依性值,因此降低了修改與擴充狀況的互相影響性值。
模組化指是將系統功能程序作分離獨立(特定功能class的容器),除了功能獨立外,也強調設計上可以根據功能隨意抽換模組。達到高內聚、低耦合的目的,進而提高開發者的生產力(將複雜的功能拆分管理)。並讓程式碼能夠透過引用的方式來重複使用,提升重用性(Reusable)
Modular design allows code to remain agile in the face of ever-changing requirements.
Propose:Module功能目標單一職責,盡量不要與其他模組設計有太多相依關係。
Interface:模組功能API所提供使用方式要簡潔易懂,通常User不需要去了解實際內部的實作方式,只需專注在確定輸入什麼,會輸出什麼可達到什麼功能。
Encapsulation:封裝模組,除了讓不暴露資料結構讓使用者亂使用外,對於在修改細節上也能較不容易直接影響使用端。另外再使用抽象實作上,物件抽象化多少還是難以避免Leaky Abstractions的問題。
Implementation:實作上除了考量功能正確性外還需考慮效能、測試與功能架構程式碼最小化。
Connection(關聯性):呼應Propose功能單一職責,將與其他模組相依性最小化。
在了解Module構成要素後~隨著專案模組(Module)的增加,將難以管理及問題的追蹤,這時候就能將模組(Module)打包成套件(Package),利用其階層式的結構來彈性規劃模組(Module)。
在非以領域事件為出發點的設計上,大部分狀況會根據功能設計成物件與介面使用。下圖為Zebra SDK Package的Module列項,我們可以大致分得出,他的Module設計就是根據功能性值去區分(graphics, certificate…)
接著我們點近discovery看提供什麼API功能,可以看到可以使用的介面功能以及相關功能可使用的功能物件。
在點進個別更詳細功能介紹,我們就會看到這物件功能具有什麼資料特質、物件實體化須提供什麼參數以及此物件可使用哪些方法。
上述為印表機找到印表機裝置功能的模組化介紹
上述一般Module設計概念聊完,在聊DDD Module設計之前先來聊一下在一般未使用DDD領域設計的服務系統會如何設計。
在對大部分的開發者,一開始習慣設計都以數據為考量的集中式設計架構。設計架構上會出現比較常見到的分層式設計,大致分成Controller, Service, Repositories, Models
上述稍微帶過Module的設計概念後,接著探討在DDD世界裡,Module的設計概念如何~大致分成幾個探討議題
在探討需求架構DDD設計的第一步,就是根據需求情境列出事件風暴(Event storming),並在事件風暴中的用戶操作、事件、以及依賴關係根據這些要素設計歸納出領域與實體。
接著第二步在領域實體之間找尋彼此務的關聯性,將具有相關的實體組合成聚合(Aggregate),同時確定聚合根(Aggregate Root)。在聚合根行程時,基本上第一層邊界(邏輯邊界-虛線)也會跟著產生,他們會在同一個服務器中運行。
當聚合規劃好後~會根據業務及語意邊界等因素,將一個或多個聚合規劃訂製在一個限界上下文內(服務邊界),形成領域模型。
Interface(API Interface)
Application
Domain
Infrastructure
例子:如何對電商平台上的顧客進行模塊設計
對於顧客來說,一般須要維護顧客的
這三個之間的關係是緊密相關,不可獨立存在,我們根據這三點抽象出三個Aggregate
那該如何去放置這些Aggregate,是針對每一個Aggregate作資料夾分類還是這三個Aggregate放同一格資料夾?基本上這三個Aggregate就是一個Custer Module,所以都會放到Custer Module資料夾內。
當整理出Aggregate與Module後,接著會開始根據各Module去實作事件應用處理
基本上我們在DDD模塊的設計上有幾個注意要點
為了對領域模型中進行準確建模,需要將領域模型劃分成多個子域,每個子域對應一個或多個限界區域。 模塊。所以,從子域到限界某些再到模塊,應該是依次包含關係。
範例
The 5 Essential Elements of Modular Software Design
The Law of Leaky Abstractions
The Three Principles of Excellent API Design
解析Python模組(Module)和套件(Package)的概念
Module Design
Domain Events vs. Integration Events in Domain-Driven Design and microservices architectures