gpt4 book ai didi

c# - 我应该从域层抽象验证框架吗?

转载 作者:IT王子 更新时间:2023-10-29 04:41:41 25 4
gpt4 key购买 nike

我正在使用 FluentValidation 来验证我的服务操作。我的代码看起来像:

using FluentValidation;

IUserService
{
void Add(User user);
}

UserService : IUserService
{
public void Add(User user)
{
new UserValidator().ValidateAndThrow(user);
userRepository.Save(user);
}
}

UserValidator 实现 FluentValidation.AbstractValidator。

DDD 说领域层必须独立于技术。

我正在做的是使用验证框架而不是自定义异常。

将验证框架放在域层是个坏主意吗?

最佳答案

就像存储库抽象一样?

好吧,即使您通过声明 IUserValidator 来保护您的域不受框架影响,我也看到您的设计存在一些问题。界面。

起初,这似乎会导致与存储库和其他基础设施问题相同的抽象策略,但我认为存在巨大差异。

使用时 repository.save(...) ,从领域的角度来看,您实际上根本不关心实现,因为如何持久化事物不是领域关注的问题。

然而,不变的执行是一个领域问题,你不应该深入研究基础设施的细节(UserValidtor 现在可以被视为这样)来查看它们的组成,这基本上是你最终会做的事情,如果你不这样做这条路径,因为规则将在框架条款中表达,并将存在于域之外。

为什么会住在外面?

domain -> IUserRepository
infrastructure -> HibernateUserRepository

domain -> IUserValidator
infrastructure -> FluentUserValidator

始终有效的实体

也许你的设计有一个更基本的问题,如果你坚持那个学派,你甚至不会问这个问题:始终有效的实体。

从这个角度来看,不变的执行是域实体本身的责任,因此在没有有效的情况下甚至不应该存在。因此,不变规则简单地表达为契约,并且在违反这些规则时抛出异常。

这背后的原因是,许多错误来自对象处于它们不应该处于的状态这一事实。公开一个我从 Greg Young 那里读到的例子:

Let's propose we now have a SendUserCreationEmailService that takes a UserProfile ... how can we rationalize in that service that Name is not null? Do we check it again? Or more likely ... you just don't bother to check and "hope for the best" you hope that someone bothered to validate it before sending it to you. Of course using TDD one of the first tests we should be writing is that if I send a customer with a null name that it should raise an error. But once we start writing these kinds of tests over and over again we realize ... "wait if we never allowed name to become null we wouldn't have all of these tests" - Greg Young commenting on http://jeffreypalermo.com/blog/the-fallacy-of-the-always-valid-entity/



现在不要误会我的意思,显然您不能以这种方式强制执行所有验证规则,因为某些规则特定于某些禁止这种方法的业务操作(例如保存实体的草稿副本),但这些规则是不可查看的与不变执行相同的方式,这是适用于所有场景的规则(例如,客户必须有一个名字)。

将始终有效的原则应用于您的代码

如果我们现在查看您的代码并尝试应用始终有效的方法,我们会清楚地看到 UserValidator对象没有它的位置。
UserService : IUserService
{
public void Add(User user)
{
//We couldn't even make it that far with an invalid User
new UserValidator().ValidateAndThrow(user);
userRepository.Save(user);
}
}

因此,此时域中没有 FluentValidation 的位置。如果您仍然不相信,问问自己您将如何集成值对象?你有没有 UsernameValidator验证 Username值对象每次实例化?显然,这没有任何意义,而且值对象的使用很难与非始终有效的方法集成。

当异常被抛出时,我们如何报告所有错误?

这实际上是我一直在努力解决的问题,我已经问自己一段时间了(我仍然不完全相信我要说的话)。

基本上,我所理解的是,收集和返回错误不是域的工作,而是 UI 问题。如果无效数据进入到域中,它只会对您产生影响。

因此,像 FluentValidation 这样的框架将在 UI 中找到它们的自然家园,并将验证 View 模型而不是域实体。

我知道,这似乎很难接受会有一定程度的重复,但这主要是因为您可能是像我一样处理 UI 和域的全栈开发人员,而实际上这些可以而且应该被查看作为完全不同的项目。此外,就像 View 模型和域模型一样, View 模型验证和域验证可能相似但服务于不同的目的。

此外,如果您仍然担心 DRY,有人曾经告诉我,代码重用也是“耦合”,我认为这一事实在这里尤为重要。

处理域中的延迟验证

我不会在这里重新解释这些,但是有多种方法可以处理域中的延迟验证,例如规范模式和 Deferred Validation Ward Cunningham 在他的 Checks 模式语言中描述的方法。如果您有 Vaughn Vernon 的《实现领域驱动设计》一书,您还可以阅读第 208-215 页。

总是一个取舍的问题

验证是一个非常困难的主题,证据是直到今天人们仍然不同意应该如何完成。有很多因素,但最终你想要的是一个实用、可维护和富有表现力的解决方案。你不能总是一个纯粹主义者,必须接受一些规则会被打破的事实(例如,为了使用你选择的 ORM,你可能不得不在实体中泄露一些不显眼的持久性细节)。

因此,如果你认为你可以接受一些 FluentValidation 细节使它进入你的领域并且它更实用的事实,那么我真的不能确定从长远来看它是否会弊大于利,但我不会。

关于c# - 我应该从域层抽象验证框架吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28395176/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com