Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DDD Entity validation

I have a question related to entity validation. As an example, there is a User which can be registered into a system given email and password. The business rule says that:

  1. email must be valid (must conform to email format) and unique;
  2. password should be between 6 and 20 characters.

My initial thought is to place the validation inside the User.Register(email, password). The main advantage of this approach is that User controls how it is registered by verifying itself the correctness of registration data. The disadvantage is that email uniqueness verification requires calls to UserRepository, so the User might have dependency on its Repository. To solve this issue, email and password validation might be factored out to some kind of BusinessRule objects. So the validation in User.Register() method might look like this:

var emailValidationErrors = _emailRule.Validate(email);
var passwordValidationErrors = _passwordRule.Validate(password);

where _emailRule and _passwordRule might be passed as constructor arguments: User(EmailRule emailRule, PasswordRule passwordRule).

In this casse User is not directly coupled to UserRepository. In this way the rules are explicitly shown in the domain, which make it more expressive.

So the question is: what do you think about this approach? Are there any other solutions?

like image 816
Markus Avatar asked Mar 10 '12 12:03

Markus


1 Answers

You could implement a Domain Service that encapsulates this. Typically in DDD you would use a Domain Service when the business logic falls outside of the scope of one individual aggregate; in this case it is the uniqueness check. So, what I'd do is:

public class UserRegistrationService : IUserRegistrationService
{
   private readonly IUserRespository _userRepository;

   public void Register(string email, string password)
   {
        if (!_userRepository.DoesEmailExist(email))
           throw new Exception("Email already registered");

        User user = User.Create(email, password);

        _userRepository.Save(user);
   }
}

Also, if you are worried about User.Create being called outside of the registration service and therefore escaping the uniqueness check, you could possibly set the User.Create method to internal, meaning the only way to create a user is via the RegistrationService.

like image 197
David Masters Avatar answered Sep 27 '22 20:09

David Masters