【发布时间】:2015-10-01 18:47:05
【问题描述】:
像 LINQ 这样的技术在描述关系数据查询方面做得很好,使用 IQueryable、IGrouping 和 IOrderedQueryable 等类型建模投影、选择 em>、聚合、排序等。这些来自关系代数的概念允许我们在一台机器上用一种语言传达相当任意的查询,并用另一种语言执行它( ~sql) 在不同的机器上。
如果能够对更复杂的多部分查询甚至涉及INSERTs、UPDATEs 和DELETEs 的数据操作命令执行相同的操作,那就太好了,描述整个操作,而不需要首先在应用层中检索/混合数据的开销,这是典型的对象-关系映射器或 ORM。
在应用程序中,我们可以描述如下操作:删除所有 Customers(以及他们的 Orders),其最近的 Order 是超过 2 年(此外,假设没有为该关系打开级联删除)。这当然比使用 t-sql 脚本的 ADO 更有效,但不能在 ORM 中完成,因为没有在应用层中选择、传输、水合和跟踪数据以及可能发出单独的删除命令的开销。 (也许 ORM 有一些优化可以在某些情况下更有效地做到这一点,但通常 AFAIK 他们不能)当然,发出 t-sql 脚本的一个问题是语句中没有类型检查,也没有任何参数或返回数据。
除了减少运行时处理和网络通信开销之外,能够为远程执行建模这些任意命令的一个惊天动地的优势是可以在应用层中编码和注册域范围的不变量,然后可以自动发出以及任何临时命令。
我们可能有一个愚蠢的域不变量A,对于所有客户,订单的每个客户的总和 价格 不能超过 10,000,000.00 美元,除非 whoa 位是 1 和另一个愚蠢的域不变量 B,上面写着 对于所有 客户, lastName 不能包含超过三个下划线(尽管这些可能可以通过数据库引擎本身的检查约束或触发器的本机机制来强制执行)。然后,当我们发出更新现有订单的 价格的命令时,系统可以通过静态分析知道该命令可能会违反不变量A,并且不变的B 不能,因此系统会在原始命令之后发出一些A 的断言。整个发出的脚本将被包装在一个事务中(如果断言失败则回滚)并且不变量可以自动缩小以仅针对特定的客户的集订单断言规则> 而不是不必要地重新检查所有 客户的总数。我相信这种优化的、集中的、DRY 的业务规则编码/执行在当今的产品中是不可能的。
为了实现这一潜力,我认为我们需要一个代数(超越SELECT 的关系代数)来描述对 INSERT、UPDATE 和 DELETE 的任意数据操作(统称为 DML) 甚至诸如中间计算值之类的东西,例如用于计算的临时表,在 t-sql 中表示为多语句列表。
不幸的是,我一直无法找到关于将 DML 形式化为代数的研究,或者能够对其建模,或者这种元编程。虽然 Tutorial-D 和 jOOq 似乎为讨论提供了一些东西——我只是不知道如何提取它。你能解释清楚吗?
一些我认为很有价值的讨论,但我想避免用它填满 cmets:
您是否建议域模型不适合保护不变量和建立事务边界?您提到的不变量使用适当的域模型并不难保护。你到底想避免什么问题?
--普拉克斯
据我了解,典型 ddd 中的大型域需要有界上下文,以避免将大型数据子集水合到应用层进行验证。我试图避免这种开销。此外,对于每个有界上下文,域不变量必须进行非平凡的重述,这很容易出错。通过对远程执行的操作进行建模,我们可以获得更智能/更小/更快/更正确的代码。
在某些核心库中,可以对域进行建模并注册不变量。然后,该库的使用者(例如 Web 服务)可以构建任意操作的类型检查描述,而无需明确考虑有界上下文或特定不变量。域核心向它的消费者提供“这是你可以在这个域上做的所有事情”,并且(也许)服务代码向它的客户提供“这些正是我们提供的功能”。
– uosɐſ
我不确定您是否正确理解限界上下文是什么以及它们如何相互通信。 “此外,对于每个容易出错的有界上下文,域不变量必须非常重要地重述/维护” 通常只有一个上下文具有数据所有权,并且该上下文应负责涉及它自己的数据的不变量。例如,想象一家在 Internet 上销售商品的公司。它们可能有一个用于维护产品的 Inventory 上下文和一个用于侦听 Inventory 中新可用产品的 Shopping 上下文。
--普拉克斯
我不太反对当前的 ddd 技术,所以我不会选择优秀的例子来反对它们。我对这种替代安排更感兴趣,我直觉它比当前的 ddd 技术更自然和先进。我见过非常交织在一起的数据模型,并且没有提供明显的界限(可能设计不佳,好吧)。我希望这种方式可以无边界且性能更高。
– uosɐſ
如果存在产品名称不能包含“宣传”一词的规则,则它只会在库存上下文中强制执行。如果我们要在每个其他上下文中复制每个上下文的不变量,那确实会成为维护的噩梦。
--普拉克斯
但您可能有一个以客户为中心的有界上下文和以订单为中心的第二个有界上下文。也许我提到的 $10,000,000.00 Limit 是 Customer 中的一列(因此是可变的),因此可以通过两种方式违反此业务规则:要么删除它限制 客户或增加订单的总数。因此,非平凡互惠规则必须根据更改检查任一有界上下文中的违规行为。如果 Prices 和 Limits 没有改变,我们的系统可能会决定跳过断言,这会很巧妙,不是吗?在传统的 ddd 中,您可能还需要一些优化的变体来进行批量操作(向每个 客户 添加一个 1000 美元的 Order),这些变体可以自动进行由我们的新系统派生而来。
– uosɐſ
【问题讨论】:
-
“对于所有客户,他们的订单价格总和不能超过 10,000,000.00 美元”:您是指他们所有订单的全球总和,还是每个客户的总和?
-
文中澄清
标签: database domain-driven-design metaprogramming dsl