在 DDD 的上下文中应该主要在哪一层进行验证?

In which layer should the validations be done mainly in the context of DDD?

这个问题可能会被问一千次,但答案中有很多困惑和矛盾。

我询问领域驱动设计中的验证

  1. 验证主要应该在哪一层进行?
  2. 对象处于无效状态是否可以接受?因为很多回答都说没问题,主要是因为历史数据和业务规则可能会随着时间的推移而改变,加载历史数据可能会导致问题?
  3. 尽管 Martin Fowler 建议 Replacing Throwing Exceptions with Notification in Validations,但许多实现考虑在域层中抛出异常并将消息映射到 UI!何时 return 消息以及何时在验证上下文中抛出异常?
  4. 许多文章在他们的文章中解释了一些提示或遵循的路径,例如 Vladimir Khorikov and jbogard,但在评论中他们承认他们现在做事有点不同。这些模式仍然有效吗?

  5. 我应该使用像FluentValidation这样的框架吗?如果我使用它,这个框架是否仅在应用程序层中用作MVC annotations的替代品?

  6. 什么时候应该使用 Business Rule Framework (BRF)

我知道这里有很多问题,但它们针对的是同一个点(DDD 中的验证)。

注意:我不使用 CQRS 模式,因为它使应用程序变得如此复杂。 所以我有 (domain layer,data layer, application layer(MVC), and shared kernel)

实际上有几种不同的活动可以称为 "validations",并且它们的处理方式都有些不同。

消息验证通常发生在我们可以管理的边界附近。当我收到一个 HTTP 请求时,我将验证请求本身是否格式正确,元数据中指定了正确的媒体类型,请求主体是否可以被干净地处理,结果 DOM具有所有必填字段,已知数据节点都是适当的类型,存在的值在允许的范围内,所有这些都在我担心域模型的当前状态之前。

通常,此验证采用将消息中的数据转换为域中值对象图的形式;这通常看起来像工厂或建造者,他们知道如何采用与领域无关的值类型并将它们转换为特定于领域的值。域模型通常不知道消息格式,也不知道序列化(JSON 通常不是域问题)。

从持久存储中读取值时,存在类似的关注点分离 - 值工厂将知道如何从基元创建值,但不一定知道任何关于 JSON 或结果集的信息,等等。

"business logic" 验证给定消息是否有意义给定域的当前状态,通常存在于域模型中。

Is it acceptable for the object to be in invalid state?

对象处于无效状态永远是不可接受的。

但有些有效状态无法到达。负账户余额正成为公司的一项重大责任,因此引入了一项新的业务规则,以防止可能导致负余额的提款。这不会改变 Bob 的账户余额为负的事实。它仍然是一个有效的状态,只是新规则无法达到的状态。

When to return messages and when to throw exceptions in the validation context ?

不要使用异常来实施应急管理。

In which layer should the validations be done mainly ?

主要在域中,除了与基础设施相关的验证,例如例如 xsd 验证或 json 架构。

Is it acceptable for the object to be in invalid state? because many answers said that it's okay and mainly because of historical data and the business rules may change over time and loading historical data might cause problems?

可以接受,因为验证是在域中进行的,所以不应该这样。从业务的角度来看,对象不能处于无效的业务状态,但是,有时,就像在现实生活中一样,流程可以处于 invalid/temporary 状态。我们称之为最终一致性(https://en.wikipedia.org/wiki/Eventual_consistency),我建议你看看这个。最终系统会处于有效状态,仅此而已,如果它暂时无效,那么维护这样的系统可能需要付出更大的努力,但有时您别无选择。

Many implementations consider throwing exceptions in the domain layer and mapping the messages to the UI although Martin Fowler recommends to Replacing Throwing Exceptions with Notification in Validations! When to return messages and when to throw exceptions in the validation context ?

我不太喜欢域层中的异常,除非这显然是一个先决条件论文被打破了。例如,某个字段的输入太大,或者某项商品的价格为负。如果您无法构建有效的业务对象,那么我认为这是一个非常有效的异常案例。如果这是一个商业案例,那么消息是最合适的。

Many articles explain some tips or paths to follow like Vladimir Khorikov and jbogard in their articles but in the comments they confess that they do things a wee differently now. Are these patterns still valid?

Should I use framework like FluentValidation and if I use it, Is this frame work used only in the application layer as an alternative to the MVC annotations ?

DDD 中的最佳建议是永远不要使用框架,Spring 或 JDBC 可能会有所帮助,但通常您应该手动完成。我们甚至手工编写了商店、应用程序服务和 Oracle 预测和事件总线。它更快,更易于维护,并且您可以学到更多。 Vaughn Vernon 在他的书(Implementing Domain Driven Design)中给出了很好的例子和一个你可以看看的项目:https://github.com/VaughnVernon/IDDD_Samples(写在Java)

When Should I use Business Rule Framework (BRF) instead?

同样,不要使用框架

您的问题有直接的答案。所以我把答案放在没有背景的地方。

In which layer should the validations be done mainly?

服务器端和客户端都可以提供更准确和安全的应用程序。无论设计上下文如何。对于服务器端,您可以采用不同的方式,例如流畅的验证或数据注释(模型),或者使用 jquery-unobtrusive-ajax 等集成库将它们带到客户端。 服务器端验证更重要,因为需要验证 CRUD 操作以避免异常等.... 就你的问题而言,图层是视图和模型(数据访问)。

Is it acceptable for the object to be in invalid state? because many answers said that it's okay and mainly because of historical data and the business rules may change over time and loading historical data might cause problems?

它是 acceptable,当您显示或处理数据库中的数据存储时,所需依赖项的必填字段或空值会引发错误。在这里,没有谈论随着时间的推移可能发生的变化。我们现在只考虑。我们使用模式和编程规则来创建 flexibility/maintainability。验证和条目依赖性可以随时间改变。

Many implementations consider throwing exceptions in the domain layer and mapping the messages to the UI although Martin Fowler recommends to Replacing Throwing Exceptions with Notification in Validations! When to return messages and when to throw exceptions in the validation context ?

在客户端显示异常是开发日或通知相应用户有关阻止数据的错误的好技术 changed/stored。 考虑到:一些系统确实没有向最终用户显示额外信息的策略。一些报告会使应用程序更容易受到入侵。这完全取决于您正在开发的软件类型。一个好的做法是在客户端显示一个简单的错误并在服务器内存储错误日志(包含全面的详细信息)。

Many articles explain some tips or paths to follow like Vladimir Khorikov and jbogard in their articles but in the comments they confess that they do things a wee differently now. Are these patterns still valid?

有些人可能有自己命名的个人架构。但其中一些是官方的并被广泛使用,例如 Unit Of WorkRepository Pattern,它们向著名模式 (MVC) 添加了一些层以实现更准确,干净且易于维护 code/application。遵循任何模式背后的主要目的。

Should I use framework like FluentValidation and if I use it, Is this frame work used only in the application layer as an alternative to the MVC annotations ? When Should I use Business Rule Framework (BRF) instead?

FluentValidationDataAnnotations 的替代品,其工作方式类似于 FluentAPI。请注意,两者都用于为属于已定义 class(数据库 table)的属性定义规则。有一个名为 ViewModel 的概念,其中包含对主模型 class (Table) 的转换(有一些更改),主要针对前端的验证。您可以将两者都用于一个项目,将每个模型映射到它的 ViewModel,反之亦然。如果您使用存储库模式,比如说,有一个数据访问层,那么一些验证就在这一层内。如果您使用的是 ViewModel,那么它位于应用程序层内。但是,作为建议,这些毫无价值。关键的成功是理解任何 technique/architecture/pattern 背后的主要目的。您可以找到关于它们每个的大量文章并专注于目标,然后您可以决定如何做以获得更多 clean/standard/maintainable/flexible/etc... 代码。

以及 最终提示:增加模块化会增加集成成本(软件成本),但会降低每个模块的成本。为您的项目使用适度的设计。有时组合架构不仅不是一个好主意,而且会增加成本和开发难度。 software design basics

中有更多详细信息