【问题标题】:How does Domain Driven Design handle Reporting?领域驱动设计如何处理报告?
【发布时间】:2012-07-18 05:56:26
【问题描述】:

如果我正在开发操作/事务类型的应用程序,我发现 DDD 很自然。但是,我总是以一种合理的方式来处理报告类型的函数。

我所说的报告不限于报告生成,还包括执行相对复杂查询的函数。 (例如,给出交易者所做的所有订单的摘要,或显示具有特定股票的交易账户的账户摘要等)。它们可以只是一些查询或支持功能,与这些操作功能一起使用。

对于这样的函数,如果我们可以在 SQL(或任何查询语言)中执行连接,获取我们感兴趣的列,并返回经过处理的结果集,那是很自然的。但是,DDD 似乎不太适合这种方式:我们需要一个额外的特殊存储库,或者让现有的最相关的存储库返回一个特殊的“实体/值对象”(这是专门的结果集)。这种特殊的“实体”实际上没有任何领域意义。

如果我们想利用有意义的领域层,这可能会产生大量来自不同存储库的额外查找,加上领域或服务层中的大量聚合工作,这很容易导致可怕的性能下降。

我也想过为这类函数设置另一个“路径”,不经过“DDD路径”,有自己的方式从数据库中获取报表数据,组合结果显示。然而这会使应用程序变得不必要的复杂,更糟糕的是,我们提供了一个额外的路径,以便更习惯于传统的面向 DB 开发的开发人员可能倾向于使用这条路径,即使它不合适。

我认为这种情况很常见(通常一个大系统不会包含操作但也包含报告和查询功能),我想知道人们是如何处理它的?

【问题讨论】:

    标签: domain-driven-design


    【解决方案1】:

    在大多数情况下,就 DDD 报告而言,它是一个单独的限界上下文和一个支持子域,在这种情况下,域驱动设计会显得过大。记住 DDD 最重要的概念:将您的建模工作集中在核心域上,并使用最简单的解决方案实现其他一切。

    【讨论】:

      【解决方案2】:

      我们最近开始使用 DDD 进行系统开发。我和你有同样的担忧,但最终选择了命令查询职责分离 (CQRS) [Fowler, Young, Dahan]。虽然它需要“数据库路径”进行查询,但我一点也不觉得直接对数据库进行命令(那些改变域状态的那些)变得很诱人。分离非常明确——命令通过域,查询直接进入数据库。

      【讨论】:

      • 老实说,很难确定哪个是正确的,但使用 CQRS 似乎最合理(这也是我从 domaindrivendesign.org 得到的最有说服力的回应)
      【解决方案3】:

      一种方法是拥有一个单独的报告系统,该系统运行来自应用数据存储的数据馈送,以更相关的格式存储数据的另一个副本。

      我使用的一种快捷方式是创建一个视图或存储过程,以将连接的数据返回到一个简单的哑对象中。

      【讨论】:

      • 事实上,您提出的两个建议就是我在原始问题中提出的建议。我希望有一些澄清或理由,以解决我的担忧。而且,再次强调一下,我所说的“报告”不一定是“报告”,也可以是一些与操作功能紧密结合的查询功能。
      【解决方案4】:

      比较复杂的查询。 (例如,给出交易者所做的所有订单的摘要,或显示具有特定股票的交易账户的账户摘要等)

      存储库执行此类任务很常见。我认为您担心如何有效地实现这一点,而答案是“延迟加载”。

      例如,让我们以“交易者所做的所有订单的汇总”为例。 “摘要”是一个报告任务,所以让我们把它放在一边。域任务是“查找交易者的所有订单”。您可能有这样的存储库方法:

      List<Order> findOrdersByTrader(Trader trader);
      

      您可以通过仅加载每个订单的最低限度(摘要)信息来实现这一点。如果您随后将存储库接口注入Order 实体,则实体本身可以在需要时调用存储库以加载其他子实体。


      更新:您的评论使问题更清楚——我之前误解了聚合部分。似乎“订单摘要”确实属于您的域。有时,一个概念是否属于域的一部分并不明显,但如果它是用户谈论的一个功能(“我想查看该交易者所下订单的摘要”)并且不存在可以执行此操作的现有对象,这是您的域中隐藏概念的标志。毕竟,您需要 一些 对象来跟踪“每只股票有多少订单”,而且这个对象没有理由不能成为您域的一部分。

      【讨论】:

      • 但这正是我在第二种选择中所担心的:利用域模型并在域/服务层进行聚合等。例如,该函数需要告诉交易者为每只股票下了多少订单。如果我们可以在查询中做,它可能是一个“比较复杂”的 sql(虽然不是那么复杂),有几十个结果。如果我们获取交易者的所有订单实体并自己进行聚合,就像获取数千条记录一样。性能差异非常明显(鉴于我仍在谈论简化案例)
      猜你喜欢
      • 2015-03-30
      • 1970-01-01
      • 2011-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多