不禁将域实体视为浪费。为啥?
Posted
技术标签:
【中文标题】不禁将域实体视为浪费。为啥?【英文标题】:Can't help but see Domain entities as wasteful. Why?不禁将域实体视为浪费。为什么? 【发布时间】:2012-06-29 03:26:21 【问题描述】:当我阅读了有关 DDD、模式和许多其他应用程序架构主题的文章时,我有一个问题一直困扰着我数月之久。我将根据 MVC Web 应用程序来构建它,但我敢肯定,问题是更广泛的。就是这样:遵守领域实体是否会在应用程序中造成僵化和低效?
DDD 方法对于管理应用程序的业务逻辑以及作为与利益相关者合作的一种方式非常有意义。但对我来说,它在多层应用程序的上下文中分崩离析。也就是说,很少有场景需要一个实体的所有数据,或者甚至两个存储库都拥有这一切。就其本身而言,这还不错,但这意味着我进行了多个查询,返回了一堆我不需要得到的一些属性。一旦完成,无关信息要么被传递到视图,要么产生丢弃、合并和映射数据到 DTO 或视图模型的开销。我需要生成大量报告,并且问题似乎在那里被放大了。每个都需要对信息进行独特的切片或聚合,SQL 可以做得很好,但存储库不能,因为它们预计会返回完整的实体。老实说,这似乎很浪费,原则上我不想破坏数据库并产生不需要的网络流量。从像Should the repository layer return data-transfer-objects (DTO)? 这样的问题看来,我并不是唯一一个为这个问题而苦苦挣扎的人。那么它似乎强加的限制的答案是什么?
感谢一个新的和困惑的 DDD-er。
【问题讨论】:
我认为这是一个很好的问题,但我认为您自己确定了差异 - 报告与行为。我担心接口激增的维护负担,但我确实发现 DDD 对逻辑和直接到 sql 的报告很有价值。 我认为你问的是一个很好的问题,这正是许多开发人员接受 CQRS 的原因。 CQRS 的进入门槛有点高,但并非不可逾越,它有巨大的好处。我会推荐这些链接:elegantcode.com/2009/11/11/cqrs-la-greg-young, martinfowler.com/bliki/CQRS.html 【参考方案1】:如果您认为完全成熟的 DDD 对于您的场景来说太过分了,那么也许您需要退一步,看看更接近 Active Record 的东西。
我使用 DDD,但在我的场景中我必须支持多个前端;几个网站和一个 WinForms 应用程序,以及一组允许与其他自动化流程交互的服务。在这种情况下,额外的复杂性是值得的。我使用 DTO 将我的数据表示传输到各个表示层。将域实体映射到 DTO 的 CPU 开销很小 - 与网络调用和数据库调用相比,这是一个舍入误差。管理这种复杂性也有开销。我通过使用AutoMapper 在一定程度上缓解了这种情况。我的存储库返回完全填充的域对象。我的服务层将映射到/来自 DTO。在这里,我们可以展平域对象、组合域对象等,以生成更表格化的数据表示。
Dino Esposito 就这个主题写了一篇 MSDN 杂志文章 here - 你可能会觉得这很有趣。
所以,我想回答您的“为什么”问题 - 像往常一样,这取决于您的上下文。 DDD可能太费劲了。在这种情况下,做一些更简单的事情。
【讨论】:
【参考方案2】:这里真正的问题是什么?处理业务规则和查询数据是两个截然不同的问题。这种认识将我们引向了 CQRS——命令-查询职责分离。那是什么?您只是不要对这两个任务使用相同的模型:领域模型是关于行为、执行业务流程、处理命令的。并且有一个单独的报告模型用于显示。通常,每个视图可以包含一个表。这些表仅包含相关信息,因此您可以摆脱 DTO、AutoMapper 等。
这两个模型如何同步?它可以通过多种方式完成:
报告模型可以建立在数据库视图之上 数据库复制 域模型可以发出包含有关每个更改的信息的事件,并且它们可以由非规范化程序处理,更新报告模型中的适当表格【讨论】:
【参考方案3】:正如我所读到的有关 DDD、模式和许多其他应用程序架构主题的文章
领域驱动设计不是关于模式和架构,而是关于根据业务领域设计代码。与其考虑存储库和层,不如考虑您要解决的问题。 “开始康复”的最简单方法是将 ProductRepository
重命名为 Products
。
遵守领域实体是否会在应用程序中造成僵化和低效?
效率低下源于糟糕的建模。 [需要引用]
DDD 方法对于管理应用程序的业务逻辑以及作为与利益相关者合作的一种方式非常有意义。但对我来说,它在多层应用程序的上下文中分崩离析。
Tiers aren't layers
也就是说,很少有场景需要一个实体的所有数据,或者甚至两个存储库都拥有所有数据。就其本身而言,这还不错,但这意味着我进行了多个查询,返回了一堆我不需要的属性。
根据需要查询该数据。不要试图将你的问题打包成一些“现成的解决方案”。相反 - 向他们学习并只应用解决问题所必需的东西。
每个都需要对信息进行唯一的切片或聚合,SQL 可以很好地执行此操作,但存储库却不能,因为它们预计会返回完整的实体。
http://ayende.com/blog/3955/repository-is-the-new-singleton
那么它似乎强加的限制的答案是什么?
“似乎”
顺便说一句,互联网上到处都是this(我指的是示例应用程序)之类的东西。 要了解 DDD 是什么,请慢慢阅读blue book。两次。
【讨论】:
【参考方案4】:每一个都需要对信息进行独特的切片或聚合,SQL 可以很好地做到这一点,但存储库却不能,因为它们预计会返回完整的实体。
将方法添加到您的存储库以仅返回您想要的内容,例如IOrderRepository.GetByCustomer 在 DDD 中完全没问题。 您也可以使用Query object pattern 或Specification 使您的存储库更通用;只记得不要在存储库的接口中使用任何特定于 ORM 的东西(例如 NHibernate 的 ICriteria)
【讨论】:
以上是关于不禁将域实体视为浪费。为啥?的主要内容,如果未能解决你的问题,请参考以下文章