2008-12-18 156 views
10

域驱动设计鼓励您使用丰富域模型。这意味着所有的领域逻辑都位于领域模型中,并且领域模型是至高无上的。持久性成为外部关注点,因为领域模型本身理想化地不知道持久性(例如数据库)。扩展丰富域模型

我在一个中等规模的单人项目(> 10万行Java)上一直在使用它,我发现了很多优点,主要是它提供的灵活性和可重构性超过了面向数据库的方法。我可以添加和删除域类,点击几个按钮,并完成一个新的数据库模式和SQL层。

不过,我经常面对在那里我发现很难与事实有一个SQL数据库备份的应用程序调和丰富域逻辑的问题。通常,这会导致典型的“1 + N查询问题”,您可以在其中获取N个对象,然后在每个对象上执行一个不重要的方法,以再次触发查询。手工优化这个功能可以让你在不断的SQL查询中完成这个过程。

在我的设计中,我允许系统插入这些优化版本。我通过将代码移动到包含数十个特定于域的查询(例如getActiveUsers)的“查询模块”中来完成此操作,内存(天真且不可扩展)和基于SQL(用于部署)的实现。这使我能够优化热点,但有两个主要缺点:

  • 我有效地移动我的一些领域逻辑的地方并不真正属于的地方,而事实上,即使将其推入SQL语句。
  • 过程需要我细读查询日志,找出热点是,在这之后我不得不重构代码,通过降低成查询降低其级别的抽象。

有调和领域驱动设计和使用的事实,你不能在内存中的所有的实体,因此被限制在后端数据库以其丰富的域模型更好,更清洁的方式?

回答

0

不,不是真的。不是说我知道无论如何(尽管我有兴趣听到任何DDD的支持者的反应)。

在我自己的经验,并且非常有经验的团队,我的工作,如果你想获得最佳性能从数据库支持的应用程序及其架构的改造是服务至上是不可避免的。我写了more about this here(本文讨论延迟加载属性,但您可以考虑将该点应用于需要检索更多数据以完成其工作的类上的任何方法)。

这么多,你现在在做什么,你可以开始了丰富的域模型并将其转换为面向服务的必要性能方面的原因。只要你定义了性能目标并且你正在达到它们,就没有必要改变一切。我认为这是一个非常体面的实用方法。

+0

我想一个真正的根本性的改善方法需要不同的语言范式,在那里你描述你的逻辑的部分声明,以便它可以自动被编译成疑问......但这种故事有其自身的问题份额: - ) – 2008-12-19 09:15:23

5

至少有两种方式来看待这个问题,一个是技术性“我能做些什么来加载我的数据更聪明”的版本。我知道的唯一真正聪明的事情是动态集合,其中部分负载按需加载,可能会预加载零件。有在JavaZone 2008 about this

一个有趣的谈话第二种方法已经比较我在我一直在与DDD的时间重点;我怎样才能让自己的模型更具“可载入性”,而不会牺牲太多的DDD优点。多年来我的假设一直是,许多DDD模型对域概念进行建模,这些域概念实际上是所有业务流程中所有允许的域状态的总和,以及随着时间的推移在每个业务流程中发生的不同状态。我相信,如果领域模型在进程/状态方面稍微更规范化,那么很多这些加载问题就会减少。这通常意味着没有“Order”对象,因为ordrer通常以多种不同的状态存在,这些状态具有相当不同的语义(ShoppingCartOrder,ShippedOrder,InvoicedOrder,HistoricalOrder)。如果你试图封装这个是一个Order对象,你总会遇到很多加载/构造问题。

但是这里没有银弹。

+0

你描述的问题主要涉及继承,代理和懒惰的状态问题(至少在我的上下文中),我已经为我的项目“解决”了它们。感谢您的建议,但我真的不知道如何改变我的模型如何表达可以改变我的问题。 – 2008-12-19 09:17:54

+0

除了当然,如果我减少数据计算,更多的数据显式存储在字段中,但这实际上是一种非规范化的形式。 – 2008-12-19 09:18:43

1

根据我的经验,这是做事的唯一方法。如果您编写的系统试图完全隐藏或抽象持久层,那么您无法使用持久层的细节优化事物。

我一直对这个问题最近跑起来一直在一个解决方案,持久层可以选择执行代表的优化接口。我刚才一直在玩它,而是用你的ListAUsers例如,它是这样的......

先写一个ListAllUsers方法,做在域级别的一切。有一段时间这将工作,然后它会开始变得太慢。

当使用丰富的域模型被缓慢创建一个名为“IListActiveUsers”的界面(或者可能是更好的东西)。并让你的持久性代码使用适合的技术来实现这个接口(可能是优化的SQL)。现在

你可以写检查这些接口,如果它存在调用具体方法层。

这不是完美的,我没有很多的经验,这样的事情。但在我看来,关键是要确保如果您使用的是完全天真的持久性方法,那么所有代码​​都应该可以工作。除此之外,任何优化都需要完成。

0

我相信你应该考虑查询层是你的域逻辑的一部分。您应该允许自己编写优化的查询,只能通过对您的持久性解决方案的“亲密”知识来完成。不要试图抽象掉一切。 另外,批处理是应用程序的另一部分,应该也允许您了解您的域。我发现没有必要尝试避免批处理,因为我无法将其纳入我的域模型。然而,您可以合并这些方法:使用查询来找出需要更改的对象,然后使用您的域逻辑对它们的ID进行排队并单独处理它们。