丰富的域模型和ORM

Alw*_*wyn 20 architecture design-patterns domain-driven-design anti-patterns

Martin Fowler认为Anemic Domain Model是一种反模式.

由于Object Relational Impedence Missmatch,将持久性模型作为域模型滚动似乎也很严重.对于持久性和规范化的问题,我们倾向于将类分解为非常小的小块,在这些类之上打字方法是愚蠢的.加上持久性很少发生变化,但业务逻辑变化很大.

所以我们需要一个基于持久性模型构建的DomainModel(而不是同一个).然后,此域模型将包含业务逻辑属性和方法.

但是现在这些领域模型仍然落后于服务,为了将它们暴露给外部世界,我们需要将它们转换为DTO.

我们在这里做的是manny mappings.

  1. 对域模型的持久性
  2. 将域模型转换为DTO以在服务之间传递

它不会在那里结束,因为DTO可能需要映射到ViewModel.

所有这些以及重复验证逻辑的问题仍然没有消失,因为客户需要实时验证.ViewModel对验证一无所知,因此在SPA中,您不得不在客户端(通常使用javascript)再次重写验证逻辑.

服务本质上是无状态的(消息或面向RPC),所以我们在Persistence,OO之间进行所有这些映射,然后返回到Procedural,有什么好处?您如何证明大多数IT预算的实际成本?

我知道如何拥有完整的DDD,使用Aggregate Roots,Domain Models等会很"酷",但你怎么能证明成本和开发效率的打击?

反模式(或反模式)是社交或商业运营或软件工程中使用的模式,可能是常用但在实践中无效和/或适得其反

如果是这样,DDD和Rich Domain Model不会适合上面的反模式定义而不是"精益"域模型.对不起,我鄙视加载的单词"Anemic".

通过保持域模型,"精益"你实际上允许它被共享而不违反"抽象依赖原则","不要重复自己"以及将一个数据载体映射到另一个数据载体的耗时,繁琐且容易出错的过程,以及除此之外的任何相关单元测试(除非您考虑使用单元测试进行映射并希望获得最佳效果).

gui*_*e31 7

看起来你混淆了很多概念,指责丰​​富的领域模型方法,而不是直接负责的事情.

  • 丰富的域模型与分层体系结构正交,特别是富域模型并没有规定您拥有的层数,这些层之间应该交换哪些数据结构以及应该如何映射它们.

  • 丰富的域模型与验证正交,并且除了后端验证之外,没有说明客户端检查的必要性.

换句话说,使用服务中的所有业务逻辑使您的域模型变得贫乏不一定会使您免于编写大量样板DTO映射代码,也不会消除客户端"双重检查"的需要(由一种普遍接受的最佳做法).

这并不意味着您对成熟的多层架构的成本和重量的观点无效.您可能会对Mark Seemann讨论类似问题的帖子感兴趣:http://blog.ploeh.dk/2012/02/09/IsLayeringWorthTheMapping.aspx


Ebe*_*oux 5

首先,我不认为您真的可以轻松摆脱在客户端服务器上复制验证逻辑。但是,这不仅限于 DDD。有一些机制可以减轻痛苦,但总是需要付出一些努力。

另一部分是整个地图业务:)

您正在做的是有效地用于执行读取。您可能认为您需要阅读您的实体才能对其进行编辑。如果您在实体对象上执行基于实体的操作(这里的 DB 术语可能更多是实体 - 整个记录),而不是基于任务的操作,则确实如此。一个愚蠢的例子可能是客户打电话到呼叫中心更改地址。接线员调出客户记录并编辑地址。这是基于实体的,并且会导致并发的典型问题,因为可能会在同一记录上执行 2 个操作(但不太可能)。这是一种非常传统的用户体验设计方法:“编辑记录”。

将其与屏幕上的按钮进行对比,该按钮显示:“更改地址”。您只需更改记录上的地址,虽然这看起来是一回事,但实际上却大不相同。2 次操作更改同一地址的机会比更改同一记录的机会要小得多。如果需要,可以在这部分进行并发检查。

现在,如果人们不阅读该域,人们会阅读什么。数据从哪里来。这就是 CQRS(命令/查询职责分离)的用武之地。过去它曾与事件溯源混淆/结合,但这不是必需的。您可以为您的应用程序创建一个简单的查询端,专注于返回您需要的数据。在 C# 中,DataRow如果它是单个实例,我使用了一个,一个DataTable用于多个实例,一个自定义 DTO 用于任何更复杂的事情。可能有一种方法甚至可以摆脱匿名类型(尚未对此进行调查)。

所以:

领域模型=操作/计算/写入查询服务=读取

在某些情况下,您可以通过简单地加载实体/聚合(例如在 Web 应用程序中)来逃避,因为它知道(或可能知道)您的域模型,但智能客户端会有点反模式。

理由相当棘手,但归结为维护。如果您的方法没有减轻您的维护负担,那么很可能是应用不正确,需要进行一些重构。

DDD 不仅与技术实现有关,尽管这有很长的路要走,朝着正确的 OO 建模方向发展。我猜无论如何其他想法都会输入到软件中,所以无论如何软件似乎都是焦点。我们都想看看橡胶与道路的交汇处。

就像大多数事情 DDD 可能会做错:)


Mik*_*eSW 5

tl; dr域模型定义不明确,它可能设计时考虑了以数据库为中心的方法.

DDD的主要目的是在代码中建模业务概念和流程.我真的怀疑你的商业概念和流程只是一揽子财产.但如果它们确实是肯定的,那么域模型可以与持久性模型相同,因此您不必进行任何映射.

持久性模型模拟对象状态的存储方式.如果您不在数据库域中,则域和持久性模型不能具有相同的目的.我在DDD中看到的最大错误之一是考虑领域模型,就像它仍然是数据驱动的.在DDD中,您没有具体的数据库.你有存储库.没有一对多,多对多等关系.没有表,也没有行.只有尝试尽可能准确地表示域的对象.

简而言之,Domain关注建模业务行为,而Persistence关心存储对象状态.我在这里看到两个不同的责任.

关于验证,您有两种类型:输入数据格式的验证,然后根据您在对象状态中更改的内容验证其他业务规则.

关于复制,我认为你指的是输入格式,但像@EbenRoux所说有机制可以帮助解决这个问题.在asp.net mvc中,大多数验证规则也包含js版本.

让我告诉你服务的一个小秘密.虽然可以在域中定义其接口,但它们的实现可以位于持久层中,从而允许它们直接与存储一起工作.由于应用程序的其余部分以抽象形式(界面)使用服务,因此只有DI容器才会知道脏密码.

DDD并不是很酷,而是根据域名设计应用程序.我敢打赌很少开发一个应用程序,唯一的目的是成为数据库的UI.大多数人的目的是通过他们的软件提供服务,以构建解决问题的虚拟产品.设计应用程序驱动您想要解决的问题而不是您刚刚使用的技术工具是有道理的.

这听起来怎么样,你想要一个砖房,但建设者说:"对不起,但我看到的只适用于木头".好吧,不要使用锯,使用其他工具可以帮助切砖.这些工具需要针对这个问题进行调整,而不是反之亦然.