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