18

Martin Fowler認爲貧血域模型是一種反模式。豐富域模型和ORM

由於Object Relational Impedence Missmatch由於域模型滾動持久性模型似乎也被嚴重關閉。對於持久化和標準化來說,我們傾向於將課程拆分爲非常小的小部分,在這些課程之上掌握方法是愚蠢的。加持久性很少改變,但業務邏輯改變了一點點。

所以我們需要一個建立在持久化模型上的DomainModel(而不是一個也是一樣的)。此域模型將包含業務邏輯屬性和方法。

但是現在這些領域模型仍然落後於服務,爲了將它們暴露給外部世界,我們需要將它們轉換爲DTO。

我們在這裏這樣做曼尼映射。

  1. 餘輝域模型
  2. 要域模型轉換爲DTO的,以服務

它並沒有結束之間傳遞下去,因爲DTO可能需要映射到視圖模型。

所有這一切以及重複驗證邏輯的問題仍然沒有消失,因爲客戶端需要實時驗證。 ViewModel對驗證一無所知,因此例如在SPA中,您不得不在客戶端重新編寫驗證邏輯(通常使用javascript)。

服務本質上是無狀態的(消息或RPC導向),所以我們正在做所有這些映射,在持久性到OO之間,然後返回到Procedural,到什麼好處?您如何證明大多數IT預算的實際成本?

我知道如何讓DDD,Aggregate Roots,Domain Models等成爲「酷」,但您如何證明成本和對開發效率的重視?

反模式(或反模式)是社交或商務 操作或軟件工程中的一個模式是可以共同使用,但 無效的和/或反作用於實踐

如果是這樣,DDD和Rich Domain Model不會比「精益」域模型適合上面的反模式定義。對不起,我鄙視加載的單詞「貧血」。

通過保持領域模型「精益」,您實際上允許在不違反「抽象依賴性原則」,「不重複自己」以及映射一個數據的耗時,乏味和容易出錯的過程中共享它載體到另一個,以及任何與之相關的單元測試(除非你正在考慮映射沒有單元測試並希望最好)。

回答

7

看來你混淆了很多概念,將責任歸咎於它不直接負責的事情的豐富域模型方法。

  • 豐富的域模型是正交的分層架構,尤其是具有豐富的域模型並沒有規定你必須層數,應該將這些層以及應如何被映射之間交換什麼數據結構。

  • 豐富的域模型是正交驗證和一無所知,除了需要對客戶端檢查到後端驗證說。

換句話說,讓您的域模型貧血與服務所有的業務邏輯並不一定會救你寫了很多的樣板DTO映射代碼,也不會刪除用於客戶端「雙重需要檢查「(這是一種普遍接受的最佳做法)。

這並不意味着您對完整的多層體系結構的成本和重量的觀點是無效的。您可能會對Mark Seemann關於此問題的興趣討論類似的問題:http://blog.ploeh.dk/2012/02/09/IsLayeringWorthTheMapping.aspx

+0

我認爲你鏈接的文章總結了困境。除了我不相信通過網絡發送域模型,這似乎是DTO的工作。在DTO上進行行爲並將其展示給客戶是沒有意義的。所以對我來說,除了他提到的3之外,架構只有「另一層抽象和映射」纔是可行的。這是一個映射!不是說爲了重用而向用戶界面引入UI關注的另一種方式是正確的。我認爲在兩極分化之間存在一個「幸福」媒介。 – Alwyn

+0

「少移動數據,事情可能變得更簡單」 - 他在文章最後的結論,對我來說聽起來像是精益模型。 – Alwyn

+0

「在DTO上進行行爲並將其展示給客戶端是沒有意義的 - 現在我理解您在富/貧域模型和分層之間建立的連接。你是否暗示應該從儘可能多的業務邏輯中剝離域對象,以便直接將它們發送到UI層而不需要DTO?還是你說的其他東西是「精益模型」? – guillaume31

2

首先我不認爲你真的可以輕鬆地擺脫服務器上客戶端上的驗證邏輯。不過,這並不侷限於DDD。有一些緩解疼痛的機制,但總是需要一些努力。

另一部分是這整個測繪業務:)

你在做什麼是有效地利用來進行讀取。您可能會認爲您需要閱讀您的實體才能編輯它。如果您在實體對象上執行基於實體的(實體可能更多使用數據庫術語 - 整個記錄)操作,而不是基於任務的操作,則情況也是如此。一個愚蠢的例子可能是,一個客戶打電話到呼叫中心更改地址。運營商調用客戶記錄並編輯地址。這是基於實體的,會導致典型問題w.r.t.併發性,因爲可以在同一記錄上執行2個動作(但不太可能)。這是一種非常傳統的UX設計方法:「編輯記錄」。

將此與屏幕上的一個按鈕進行對比:「更改地址」。你只能改變記錄中的地址,雖然這看起來是一樣的,但它確實是完全不同的。 2次操作改變相同地址的機會比改變相同記錄的機會要小得多。如果需要的話,可以對這部分進行併發檢查。

現在,如果一個人不讀取域會讀什麼。數據從哪裏來。這就是CQRS(命令/查詢責任分離)進來的地方。過去它已經與事件採購混淆/組合,但這不是必需的。您可以爲您的應用程序創建一個簡單的查詢端,專注於返回您需要的數據。在C#中,如果它是單個實例,則使用DataRow;對於多個實例,我使用DataTable;對於更復雜的任何東西,我使用自定義DTO。可能有一種方法甚至可以脫離匿名類型(還沒有調查過)。

因此:

域模型=操作/計算/寫 查詢服務=讀

有情況下,你可以簡單地加載實體/集料,例如這是因爲它的web應用程序脫身知道(或可能意識到)你的域模型,但智能客戶端會有點反模式。

理由是相當棘手,但它確實歸結爲維護。如果你的方法不能減輕你的維護負擔,那麼機會是不正確的應用,需要一些重構。

DDD不僅僅是關於技術實現,儘管這有很長的路要走,推動了適當的OO建模方向。無論如何,我想其他的想法都會融入到軟件中,所以軟件似乎成爲了焦點。我們都希望看到橡膠在哪裏與路面相遇。

最喜歡的事情DDD可以冤屈:)

4

文藝青年最愛的領域模型沒有很好地定義,它可能設計時考慮分貝爲中心的方法。

DDD的主要目的是在代碼中對業務概念和流程進行建模。我真的懷疑你的業務概念和流程只是一袋財產。但是,如果他們真的是這樣,那麼領域模型可以和持久性模型一樣,所以你不必做任何映射。

持久性模型模型如何存儲對象狀態。如果您不在數據庫領域,那麼域和持久性模型不能具有相同的目的。我在DDD看到的最大的錯誤之一是考慮域模型,就像它仍然是數據驅動的。在DDD中,您沒有具體的數據庫。你有存儲庫。沒有一對多,多對多的關係。沒有表和沒有行。只有儘可能準確地表示域的對象。

簡單地說,域名關心業務建模行爲而持久關心存儲對象的狀態。我在這裏看到兩種不同的責任。

關於驗證,你有2種類型:輸入數據的驗證格式,然後根據你的對象狀態改變什麼的其他業務規則驗證。

關於重複,我想你指的是輸入格式,但像@EbenRoux說有機制可以與幫助。在asp.net mvc中,大多數驗證規則都包含js版本。

讓我告訴你的服務的一個小祕密。雖然可以在域中定義它們的接口,但它們的實現可以位於持久層中,從而允許它們直接使用存儲。由於應用程序的其餘部分以抽象形式(界面)使用服務,因此只有DI容器纔會知道這個骯髒的祕密。

DDD是不是裝酷,它是關於根據域設計的應用程序。我敢打賭,幾乎沒有人開發一個應用程序,唯一的目的是成爲數據庫的用戶界面。大多數人的目標是爲他們的軟件提供服務,以構建解決問題的虛擬產品。 它是有道理的,設計的應用程序來驅動你想解決的問題,而不是你碰巧使用的技術工具。

如何做到這一點的聲音,你想有一個磚房子,但構造說:「很抱歉,但我只看到了有木作品」。那麼,不要使用鋸子,使用另一種工具來幫助切割磚塊。這些工具需要根據問題進行調整,而不是反之。

+0

因此,DDD中的域是有狀態的還是無狀態的?域名是否應該公開其屬性?如果不是什麼將是域方法的參數和返回類型?,DTO?如果它確實暴露了它的特性,這比貧血模型更好嗎? – Alwyn

+0

域主要是關於行爲。當然,域對象可以具有屬性,但它不具有唯一屬性。這些屬性不僅是原始的。如何直接在列中保存IFormattedContent?我開始認爲你現在的域名只是一個數據驅動程序代碼的集合,它只是使用DDD術語。 – MikeSW

+0

@Alwyn域的一部分是有狀態的 - 正是實體具有狀態以及身份的重點,以便我們可以跟蹤該狀態的變化。另一方面,價值對象不是有狀態的(如果你願意的話,它是狀態凍結的)。域服務顯然應該是無狀態的。 – guillaume31