1. 程式人生 > >.NET領域驅動設計—初嘗(原則、工具、過程、框架)

.NET領域驅動設計—初嘗(原則、工具、過程、框架)

事物 只需要 pos eight 封裝 bili 建模 成就 一個

閱讀目錄:

  • 1.原則
    • 1.1.精簡聚合
    • 1.2.分離用例與接口功能(設計模式的用武之地)
  • 2.工具、框架、組件
  • 3.過程

1】原則

原則對於任何一項技術實現來說都是至關重要的,在設計某一個系統功能的時候我們講究的是設計原則:

單一職責原則Single Responsibility Principle、裏氏替換原則Liskov Substitution Principle、依賴倒置原則Dependence Inversion Principle、接口隔離原則Interface Segregation Principle、迪米特法則Law Of Demeter、開閉原則Open Close Principle

】。

在架構設計的時候我們也講究架構原則:

【分層原則、避免循環依賴】。

不僅僅在技術領域在做人做事都要講究原則,違背原則那麽等待你的將是無情的懲罰。

對於DDD的設計我們也有相應的原則需要遵守,當然如果不遵守在前期看不出什麽區別,但是到開發階段問題就會暴露出來。

我們來看兩個基本的設計原則問題。

【精簡聚合】

精簡聚合的設計原則無疑是最重要的。一些軟件工程方法論書籍經常指導我們進行UML業務建模,"在這個階段不需要考慮任何技術實現問題”,我按照這樣的指導原則進行了UML的設計然後順利的創建出ER關系圖,結果發現那樣的數據庫結構根本不能作為最終的項目開發數據庫。哪裏出問題了?我反復查詢指導書籍後來在專業的DDD書籍上看到了一句大概這樣的話:

  • 【“不以技術實現為前提的設計都是紙上談兵”】

我想這句話很真實的描述了方法論與企業應用之間的鴻溝,很多技術思想或者理論確實很好,但是要想用起來需要解決很多問題。DDD也避免不了這個問題,怎麽避免在設計UML模型的時候不會導致設計過度的問題,這裏我們只需要遵守【精簡聚合】原則就不會導致設計過度問題。

在前面的例子當中我們設計一個完整的UML領域模型,但是我們並沒有對它進行【精簡聚合】重構,所以它存在的問題就是無法進行項目開發。

1.1圖

技術分享

我們構建出來的領域模型初步版本應該是上圖這樣的,實體與實體之間是有強聯系的,聚合之間的關聯太大,導致牽一發而動全身。如果按照這種關系創建數據庫那麽數據庫之間的主\外鍵肯定很多,對數據庫的設計造成了影響。這樣的關系如果在程序中使用也會存在很多問題,我們無法進行少數聚合的使用,當我們使用某一個聚合的時候它會接二連三的把相關聯的聚合都給拖出來,不僅在查詢的時候妨礙而且在Factory創建聚合的時候也會存在無法構造的問題,不管在對聚合Repository進行任何操作的時候都會影響程序邏輯,所以我們需要對一個復雜的龐大的關系進行拆分。

將紅線的部分全部斷開,聚合之間通過Id進行關聯,這樣就會變的很清晰。因為很少程序中會在某一個業務邏輯點上需要所有的業務模型參與,這樣既方便了程序的開發也方便了數據庫的設計,更方便了ORM的使用。ORM的延遲加載其實就是為了聚合之間的依賴,可以在需要的時候在去查詢需要的模型。但是這樣雖然程序可以說的過去,那麽數據庫的設計就說不過去了。對於不同的ORM框架的映射原理不同,在構造模型的時候是需要稍微的調整的,比如在EntityFramework中,它能支持的映射方案你保證你的模型能順利的映射過去,這裏就不扯了後面有一個詳細的項目做全面實踐,到時候在具體問題具體分析。

最後我們看一下分解後的類圖:

1.2圖

技術分享

這樣一來一塊一塊很清晰,都能直接使用相關的核心領域模型,也不需要擔心ORM框架的延遲加載的問題。

【分離用例與功能接口(設計模式的使用之地)】

分離用例與功能接口其實也是初次接觸DDD的朋友都會犯的職業病,因為我們都熟悉面向對象設計。在進行UML建模的時候我們都非常喜歡抽象,會很清楚的把具有泛化關系的用繼承來表示,比如【用戶類型】,不同的用戶具有不同的行為權限,在初步設計的時候我們一般都會建立關於用戶的一個繼承關系來表達泛化的業務模型。但是在編碼階段會發現很明顯的問題就是我們把關於Repository的行為包含到了發起用例的用戶聚合當中去了,這樣說可能有點抽象。我們還是用例子來分析;

1.3圖

技術分享

上圖中我將【Admin】和【配送】用例分開了,想表達是不能將關於配送的行為放在【Admin】中。在我們對有關權限進行建模的時候經常會潛意識的將各自的行為放在了各自的角色當中,如果後期存在多角色共享行為的就將寫在抽象的類中使用虛方法向下傳遞。問題就出在關於角色行為裏,我們知道如果有行為那麽就有可能在該行為裏面執行有關其他聚合的IRepository操作,這樣一來將會把領域模型搞的很亂,無法垂直分析。

1.4圖

技術分享

DDD講究領域驅動,在我們看來【Dispatching】、【CheckOrders】都是繼承管理員角色,管理員屬於後臺管理人員,意味著企業的員工。對消費者來說他們就是管理人員。同樣消費者也會存在相同的情況,消費者可能存在很多種類型,有VIP系列的(VIP1\VIP2\VIP3…),有鉆石會員之類的。如果這樣設計的話並不能說是錯的,這也完全符合DDD的思想要求,但是實際情況下卻是不理想的。

這裏就用到了我們長期使用的設計模式了,我們可以通過設計模式中的很多中模式來將用戶與行為分離開來,再將使用的規則條件抽象出來就完全獨立了用戶,用戶在使用的時候不會存在直接的行為歸屬,但是事實上他們確實是有行為。

1.5圖

技術分享

用專業的DDD術語講“規約模式”,將業務規則抽取出來對象化,甚至到最後都可以進行規則的配置化。最讓我們興奮的是,我們苦心學習的設計模式終於可以在系統設計中大面積的使用了,難道不是一件很驚喜的事情嗎!

2】工具、框架、組件

任何一種架構都是需要框架、工具的支撐才能變的完美。

當我們在某種架構下進行開發的時候,我們必須需要很多工具、框架的支撐才能讓開發工作變的很便捷,這也和【敏捷開發】的思想一樣。在傳統的三層架構下開發我們都需要 "對象映射"、"AOP\IOC” 等等類似的輔助框架,目的是為了架構前行的可能性。在DDD中我們也需要很多目前還沒有出現的很多工具、框架,在.NET平臺中目前來看只有EntityFramework框架算是為了DDD做了很多工作,如果我們的領域模型無法與數據庫進行映射,那麽領域模型開發所要付出的代價將是很大。

在設計階段我們缺乏一個面向特定領域的建模工具,這種工具與UML不同,UML太技術化通用化。DDD中經常會提起【領域專家】一角,他是最具有權威性的領域領頭人,我們所創建出來的UML他們未必能看得懂,通過技術人員技術化之後形成UML其實已經變味,【領域專家】是懂非懂的無法做到肯定的保證。如果能把領域模型語言化,那麽這個將是一大成就。【領域專家】對領域中的任何事物、人物、環節都很熟悉,但是他無法表達清楚自己的想法,如果能有一個工具輔助他的設計,該工具能將設計後的模型進行平滑等價的技術化變成代碼模型或者數據庫模型,這一條鴻溝如果能跨越那麽對行業來說具有很大影響力。

1.8圖

技術分享

如果我們能等價的將上圖中的真實模型進行技術化,那麽真的每個人都會喜歡需求分析、分析設計。

既然是模型驅動設計,我們在給用戶分析類似這樣一套系統的時候,前提是我們已經對裏面的所有細節進行了抽象封裝,每一個過程都是可以拆分的,最後能合並在一起形成一個整體的業務模型。當然這裏只是一種技術展望,也是我們奮鬥和理想的目標。

推薦一本最新Martin Fowler的書:《領域特定語言》

3】過程

DDD不是一種純技術實現,而是一整套開發思想,它貫穿軟件開發的所有生命周期。從我們開發接觸領域,對領域知識進行深入的消化,這些都是DDD所強調的。那麽在我們日常開發過程中,我們該如何處理這些過程,需求不會再像以前那樣是一份雜亂無章的草稿,而是一個內容豐富的領域模型草圖。這樣的要求對團隊對部門甚至對公司來說都是一個提升,要想做到完全的DDD過程其實很難。

公司領導如何看待這樣的開發方式,我們多數人都是在一些非專業研發類的公司工作,領導希望能盡早的看到東西,這很矛盾,需要好的東西但是不按照好的東西做法來做。如果有幸能有一個面向DDD、敏捷、XP的研發團隊工作,那麽可以視項目為一件終身的藝術品。

這兩篇文章主要是一些本人對DDD的感悟,分享給大家。

後面一篇文章將會詳細的使用一個DDD架構的小系統作為案例給大家分享,裏面將包括從需求的分析建模、設計模式的使用、數據庫映射、EntityFramework的使用等等,可以作為真實項目開發的依據。

.NET領域驅動設計—初嘗(原則、工具、過程、框架)