验证应主要在DDD的哪一层进行?

时间:2018-09-26 12:07:29

标签: asp.net-mvc validation design-patterns domain-driven-design enterprise

这个问题可能被问过一千遍,但是答案中却有很多困惑和矛盾。

我询问有关域驱动设计的验证

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

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

  6. 何时应改为使用Business Rule Framework (BRF)

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

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

3 个答案:

答案 0 :(得分:3)

  

主要应在哪一层进行验证?

主要在域中,但与基础架构相关的验证除外,例如例如xsd验证或json模式。

  

对象处于无效状态是否可以接受?因为很多   回答说还可以,主要是因为历史数据和   业务规则可能会随时间变化并加载历史数据   可能会引起问题?

这是可以接受的,因为验证不是在域中完成的。从业务的角度来看,对象不能处于无效的业务状态,但是有时,就像在现实生活中一样,流程可能处于无效/临时的状态。我们称其为最终一致性(https://en.wikipedia.org/wiki/Eventual_consistency),建议您对此进行一下了解。最后,系统将处于有效状态,这很重要,如果它暂时无效,那么维护此类系统的工作可能会更大,但有时您别无选择。

  

许多实现都考虑在域层中引发异常   并将消息映射到UI,尽管Martin Fowler建议   用验证中的通知替换抛出异常!   何时返回消息以及何时在验证中引发异常   上下文?

我不是领域层异常的忠实拥护者,除非这显然是先决条件。例如,对于字段而言输入太大,或者某项商品的价格为负数。如果您不能构建有效的业务对象,那么我认为这是一个非常有效的例外情况。如果这是业务案例,则最适合发送消息。

  

许多文章都解释了一些提示或方法,例如弗拉基米尔(Vladimir)   Khorikov和jbogard在他们的文章中但在评论中,   坦白说,他们现在做事不一样了。这些模式是   仍然有效吗?

     

我应该使用FluentValidation这样的框架吗?如果使用它,这是   框架仅在应用程序层中用作替代   MVC批注?

DDD中的最佳建议是永远不要使用框架,但是Spring或JDBC可能会有所帮助,但是总的来说,您应该手工完成。我们甚至手工编写了商店,应用程序服务以及Oracle预测和事件总线。它更快,更易维护,您会学到更多。沃恩·弗农(Vaughn Vernon)在他的《实现域驱动的设计》一书中提供了很好的示例和一个项目,您可以查看:https://github.com/VaughnVernon/IDDD_Samples(用Java编写)

  

何时应改为使用业务规则框架(BRF)?

再次,不要使用框架

答案 1 :(得分:2)

实际上有几种不同的活动可以称为“验证”,它们的处理方式有所不同。

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

通常,这种验证采取将消息中的数据转换为域中的值对象图的形式;通常看起来像工厂或构建者,他们知道如何获取域不可知的值类型并将其转换为特定于域的值。域模型通常对消息格式一无所知,并且对序列化一无所知(JSON通常不是域关注的问题)。

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

“业务逻辑”通常用于域模型中,该逻辑用于验证给定消息鉴于域的当前状态是否有意义。

  

对象处于无效状态是否可以接受?

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

但是存在不能可达的有效状态。负帐户余额正成为公司的重要负债,因此引入了新的业务规则,该规则可防止可能导致负余额的取款。但这并没有改变鲍勃的帐户余额为负的事实。它仍然是有效状态,只是新规则无法达到的状态。

  

何时返回消息以及何时在验证上下文中引发异常?

请勿使用异常来实施应急管理。

答案 2 :(得分:2)

对于您的问题有直接的答案。所以我没有背景就回答了。

  

主要应在哪一层进行验证?

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

  

对象处于无效状态是否可以接受?因为很多   回答说还可以,主要是因为历史数据和   业务规则可能会随时间变化并加载历史数据   可能会引起问题?

当您显示或处理数据库中的数据存储时,可接受的必需字段或必需依赖项的空值会引发错误。在这里,没有谈论随着时间的推移而发生的变化。我们现在才考虑。我们采用模式和编程规则来创建灵活性/可维护性。验证和条目依赖关系可以随时间更改。

  

许多实现都考虑在域层中引发异常   并将消息映射到UI,尽管Martin Fowler建议   用验证中的通知替换抛出异常!   何时返回消息以及何时在验证中引发异常   上下文?

在开发日中,在客户端显示异常是一种不错的技术,也可以通知相应的用户有关错误的信息,该错误会导致数据无法更改/存储。 考虑:某些系统确实没有策略向最终用户显示其他信息。一些报告会使该应用更容易受到入侵。这完全基于您正在开发的软件类型。一个好的做法是在客户端显示一个简单的错误,并将错误日志存储在服务器内部(具有全面的详细信息)。

  

许多文章都解释了一些提示或方法,例如弗拉基米尔(Vladimir)   Khorikov和jbogard在他们的文章中但在评论中,   坦白说,他们现在做事不一样了。这些模式是   仍然有效吗?

某些人可能拥有带有自己命名的个人架构。但是其中有些是官方的,并且被广泛使用,例如工作单元存储库模式,它们为著名的模式(MVC)添加了一些层,以实现更准确,清洁和可维护的代码/应用。遵循任何模式背后的主要目的。

  

我应该使用FluentValidation这样的框架吗?如果使用它,这是   框架仅在应用程序层中用作替代   MVC注释?什么时候应该使用业务规则框架(BRF)   代替?

FluentValidation DataAnnotations 的替代方法,其作用类似于 FluentAPI 。请注意,两者都用于定义属于已定义类(数据库表)的属性的规则。有一个名为 ViewModel 的概念,其中包含对Main Model类(表)的转换(有些更改),主要针对前端的验证。您可以将两者同时用于一个项目,将每个模型映射到其ViewModel,反之亦然。如果您使用的是存储库模式,比如说有一个数据访问层,那么一些验证就在该层内部。如果您使用的是ViewModel,则它位于应用程序层内。但是,作为建议,这些都是毫无价值的。成功的关键在于了解任何技术/体系结构/模式背后的主要目的。您可以在它们周围找到大量文章,并专注于目标,然后可以决定要做什么以拥有更干净/标准/可维护/灵活/等...的代码。

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

中有更多详细信息