學習了DDD N-Layered一段時間,發現真的是博大精深。
說到DDD N-Layered,下面這張圖,一定不陌生。
這邊我不打算講解這張圖,如果你想了解更多關於DDD N-Layered的知識,
可以到這邊下載電子書http://microsoftnlayerapp.codeplex.com/documentation
共有下面這幾個章節可以學習
– Chapter 1: Architecture Guide Introduction
– Chapter 2: The Architecture Design Process
– Chapter 3: N-Layered Architecture (Global Vision)
– Chapter 4: The Data Persistence Infrastructure Layer
– Chapter 5: The Domain Model Layer
– Chapter 6: The Application Layer
– Chapter 7: The Distributed Service Layer
– Chapter 8: The Presentation Layer
– Chapter 9: Cross-cutting Infrastructure Layers
– Chapter 10: Architecture and Patterns in ‘Cloud-Computing’ PaaS and Windows Azure
好了,本篇文章的主題開始,就是開始聽我講一些有的沒的。
其實我覺得DDD N-Layered Architecture(以下簡稱DDD)是一個很好的架構,
非常的適合大型專案與多人合作的環境。
如果完全的遵守DDD的規則來寫程式(1人專案),你會發現1個月後,你自己寫的程式,自己都看不太懂。
因為切的很細,實作的細節非常多。
舉個例子來說。如果依照DDD來實作(請看上圖)的話,每層的參考關係應該如下。
UI —> Application Layer —> Domain Model Layer <— Infrasturcture Layer for Data Persistence(Data Access Layer)
如果以.Net來實作的話,共會有4個專案。分別是UI、Application Layer、Domain Model Layer、Data Access Layer,特別的是Domain Model Layer不參考任何Layer。。
理論上UI那層不能夠直接存取到DB。必需透過Application Layer,Application Layer再去跟DataAccess Layer要資料,
因為這個專案有使用ORM,所以DataAccess Layer需要參考到Domain Model Layer的ORM Entity。
頭昏了嗎? 這還只是前菜,DDD整個存取模式的概觀。
接下來才是主菜。
因為UI那層看不到Domain Model Layer,UI也不知道什麼ORM Entity。
所以在Application Layer必需使用DTO(Data Transfer Object)來回傳資料,什麼是DTO? 有興趣的可以參考這篇。
In 91 Blog 的[工作心得]傳統程式架構到3-Layer架構的心路歷程
「理論上」ORM Entity 產生出來的Class是不太適合拿來當DTO的,因為如果ORM Entity產生出來的Class有變,
那麼前端的DTO結構就會受到影響,有可能會造成問題。
所以為了這個理論,在實作上程式就會非常的複雜。以下我就說幾個CRUD(Create、Read、Update、Delete) with ORM,且使用DTO的流程。
Create:
UI -> 把資料塞到DTO -> 把DTO傳到Application Layer -> Application Layer 把資料轉換成ORM Entity
-> 把ORM Entity傳到DataAccess Layer -> DataAccess Layer 把 ORM Entity 新增到資料庫 -> 完成。
Read:
UI -> 把查詢條件傳到Application Layer -> 依查詢條件向DataAccess Layer要資料
-> DataAccess Layer查到資料後回傳ORM Entity給Application Layer -> Application Layer 把 ORM Entity 轉換成DTO
->回傳DTO到UI ->完成
Update:
UI -> 把資料塞到DTO -> 把DTO傳到Application Layer -> Application Layer 把資料轉換成ORM Entity
-> 把ORM Entity傳到DataAccess Layer -> DataAccess Layer 依據傳進來的資料,使用ORM向資料庫查詢此筆資料,
並假設此筆資料名為UpdateRow1 -> 把要更新的資料一筆一筆的對映到剛剛查到的資料(UpdateRow1) ->
把更新後的資料(UpdateRow1)更新回資料庫中 -> 完成。
Delete:
UI -> 把刪除資料的條件傳到Application Layer -> 把刪除資料的條件傳到DataAccess Layer
->DataAccess Layer 依據傳進來的刪除條件,使用ORM向資料庫查詢此筆資料,並假設此筆資料名為DeleteRow1
-> 刪除此筆資料 -> 完成。
看到了嗎,上面就是要實現DDD所要付出的「代價」,幾乎就是 DTO 跟 ORM Entity在那邊轉來轉去。
不可否認DDD在多人、大型的專案下,的確有好處。
但是事實上,在台灣很多都是1人專案,這樣子搞,只會把自己搞死,萬一下一個接手的不會、也沒聽過DDD,
那就是整個系統砍掉重練。
用個比較生活化的例子來說:
你預計2年後要結婚,然後到時候需要有一棟房子住,而這棟房子你想自己1個人蓋(了不起3個人)。
這時候你會蓋一間小平房,能力好一點就蓋一棟透天厝。
但你總不可能為了考量到以後你要生3個小孩、把父母接過來、開一間公司,所以要把這房子蓋成商業大樓吧。
零零總總其實就是時程、品質、成本的考量與取捨。所以我想說的是,
不要為專案的未來做過多的假設,當然適度的假設是一定要的。
寫到這邊,你一定會覺得我在說DDD很爛,叫大家不要用。
其實不是的,我自己本身也很討厭那種1個檔案寫了好幾萬行的程式,全部黏在一起。
相反的我覺得DDD是個好架構,但是時程、人力、成本上的考量,我想要對DDD做一些修改,
讓程式簡化,但也保留了部份日後修改程式的彈性。
但修改會失去DDD架構中部份的彈性,所以這部份就見人見智了,
寫軟體沒有什麼方法是絕對好的,只有相對適合的方法。
上面CRUD(Create、Read、Update、Delete)的例子,很多工都卡在 DTO 與 ORM Entity 的互轉。
所以我想把這個部份省掉,做法就是讓UI這層直接參考到Domain Model Layer,
這樣子一來,就可以把 DTO 與 ORM Entity 互轉的工省掉了。每一層都直接用 ORM Entity Class來傳遞送。
如下圖所示。
但這樣子做,代表前端的UI層與Domain Model Layer綁在一起了,日後如果ORM的模型如果有變,
前端UI的程式碼也會影響到,但相較於日後程式的可維護,我想對於1人專案來說,這是值得的。
如果你有更好的想法或是想發表一下見解,也歡迎於此篇文章中留言,大家一起討論。