我应该从域层抽象验证框架吗? [英] Should I abstract the validation framework from Domain layer?

查看:21
本文介绍了我应该从域层抽象验证框架吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using FluentValidation to validate my service operations. My code looks like:

using FluentValidation;

IUserService
{
    void Add(User user);
}

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

UserValidator 实现 FluentValidation.AbstractValidator.

UserValidator implements FluentValidation.AbstractValidator.

DDD 表示领域层必须独立于技术.

DDD says that domain layer have to be technology independent.

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

What I am doing is using a validation framework instead of custom exceptions.

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

It's a bad idea to put validation framework in the domain layer?

推荐答案

就像仓库抽象一样?

好吧,即使您通过声明一个 IUserValidator 接口来保护您的域不受框架的影响,我也发现您的设计存在一些问题.

Just like the repository abstraction?

Well, I see a few problems with your design even if you shield your domain from the framework by declaring an IUserValidator interface.

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

At first, it seems like if that would lead to the same abstraction strategy as for the Repository and other infrastructure concerns, but there's a huge difference in my opinion.

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

When using repository.save(...), you actually do not care at all of the implementation from the domain perspective, because how to persist things is not a domain concern.

然而,不变性实施是一个领域问题,您不应该深入研究基础设施细节(UserValidtor 现在可以这样看待)来了解它们的组成,这基本上就是您如果你沿着这条路走下去,最终会这样做,因为规则将在框架条款中表达并且存在于域之外.

However, invariant enforcement is a domain concern and you shouldn't have to dig into infrastructure details (the UserValidtor can now be seen as such) to see what they consist of and that's basically what you will end up doing if you do down that path since the rules would be expressed in the framework terms and would live outside the domain.

为什么它会住在外面?

domain -> IUserRepository
infrastructure -> HibernateUserRepository

domain -> IUserValidator
infrastructure -> FluentUserValidator

始终有效的实体

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

Always-valid entities

Perhaps there's a more fundamental issue with your design and that you wouldn't even be asking that question if you adhered to that school of though: always-valid entities.

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

From that point of view, invariant enforcement is the responsibility of the domain entity itself and therefore shouldn't even be able to exist without being valid. Therefore, invariant rules are simply expressed as contracts and exceptions are thrown when these are violated.

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

The reasoning behind this is that a lot of bugs comes from the fact that objects are in a state they should never have been. To expose an example I've read from Greg Young:

假设我们现在有一个 SendUserCreationEmailServiceUserProfile ... 我们如何在该服务中合理化 Name 是不是null?我们再检查一下吗?或者更有可能......你只是不费心去检查和希望最好"你希望有人打扰在发送给您之前对其进行验证.当然使用 TDD 之一我们应该编写的第一个测试是,如果我向客户发送应该引发错误的 null 名称.但是一旦我们开始写作这些类型的测试一遍又一遍,我们意识到......等等,如果我们永远不允许名称变为空,我们不会进行所有这些测试"- Greg Young 评论 http://jeffreypalermo.com/blog/the-fallacy-of-the-always-valid-entity/

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/

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

Now don't get me wrong, obviously you cannot enforce all validation rules that way, since some rules are specific to certain business operations which prohibits that approach (e.g. saving draft copies of an entity), but these rules aren't to be viewed the same way as invariant enforcement, which are rules that applies in every scenarios (e.g. a customer must have a name).

如果我们现在查看您的代码并尝试应用始终有效的方法,我们会清楚地看到 UserValidator 对象没有它的位置.

If we now look at your code and try to apply the always-valid approach, we clearly see that the UserValidator object doesn't have it's place.

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 值对象?显然,这没有任何意义,而且值对象的使用很难与非始终有效的方法集成.

Therefore, there's no place for FluentValidation in the domain at this point. If you still aren't convinced, ask yourself how you would integrate value objects? Will you have a UsernameValidator to validate a Username value object everytime it's instanciated? Clearly, that doesn't make any sense and the use of value objects would be quite hard to integrate with the non always-valid approach.

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

That's actually something I struggled with and I've been asking that myself for a while (and I'm still not entirely convinced about what I'll be saying).

基本上,我了解到的是,收集和返回错误不是域的工作,而是 UI 问题.如果无效数据进入到域中,它只会向您抛出.

Basically, what I've come to understand is that it isn't the job of the domain to collect and return errors, that's a UI concern. If invalid data make it's way up to the domain, it just throws on you.

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

Therefore, frameworks like FluentValidation will find their natural home in the UI and will be validating view models rather than domain entities.

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

I know, that seems hard to accept that there will be some level of duplication, but this is mainly because you are probably a full-stack developer like me that deals with the UI and the domain when in fact those can and should probably be viewed as entirely different projects. Also, just like the view model and the domain model, view model validation and domain validation might be similar but serves a different purpose.

另外,如果你仍然担心 DRY,有人曾经告诉我代码重用也是耦合",我认为这个事实在这里尤为重要.

Also, if you're still concerned about being DRY, someone once told me that code reuse is also "coupling" and I think that fact is particularly important here.

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

I will not re-explain those here, but there are various approaches to deal with deferred validations in the domain such as the Specification pattern and the Deferred Validation approach described by Ward Cunningham in his Checks pattern language. If you have the Implementing Domain-Driven Design book by Vaughn Vernon, you can also read from pages 208-215.

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

Validation is an extremely hard subject and the proof is that as of today people still don't agree on how it should be done. There are so many factors, but at the end what you want is a solution that is practical, maintainable and expressive. You cannot always be a purist and must accept the fact that some rules will be broken (e.g you might have to leak some unobtrusive persistence details in an entity in order to use your ORM of choice).

因此,如果您认为您可以接受一些 FluentValidation 详细信息已进入您的域并且它更实用的事实,那么我真的无法确定从长远来看它是否弊大于利跑,但我不会.

Therefore, if you think that you can live with the fact that some FluentValidation details makes it to your domain and that it's more practical like that, well I can't really tell if it will do more harm than good in the long run but I wouldn't.

这篇关于我应该从域层抽象验证框架吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆