Domain Validation in a CQRS architecture
Asked Answered
C

12

51

Danger ... Danger Dr. Smith... Philosophical post ahead

The purpose of this post is to determine if placing the validation logic outside of my domain entities (aggregate root actually) is actually granting me more flexibility or it's kamikaze code

Basically I want to know if there is a better way to validate my domain entities. This is how I am planning to do it but I would like your opinion

The first approach I considered was:

class Customer : EntityBase<Customer>
{
   public void ChangeEmail(string email)
   {
      if(string.IsNullOrWhitespace(email))   throw new DomainException(“...”);
      if(!email.IsEmail())  throw new DomainException();
      if(email.Contains(“@mailinator.com”))  throw new DomainException();
   }
}

I actually do not like this validation because even when I am encapsulating the validation logic in the correct entity, this is violating the Open/Close principle (Open for extension but Close for modification) and I have found that violating this principle, code maintenance becomes a real pain when the application grows up in complexity. Why? Because domain rules change more often than we would like to admit, and if the rules are hidden and embedded in an entity like this, they are hard to test, hard to read, hard to maintain but the real reason why I do not like this approach is: if the validation rules change, I have to come and edit my domain entity. This has been a really simple example but in RL the validation could be more complex

So following the philosophy of Udi Dahan, making roles explicit, and the recommendation from Eric Evans in the blue book, the next try was to implement the specification pattern, something like this

class EmailDomainIsAllowedSpecification : IDomainSpecification<Customer>
{
   private INotAllowedEmailDomainsResolver invalidEmailDomainsResolver;
   public bool IsSatisfiedBy(Customer customer)
   {
      return !this.invalidEmailDomainsResolver.GetInvalidEmailDomains().Contains(customer.Email);
   }
}

But then I realize that in order to follow this approach I had to mutate my entities first in order to pass the value being valdiated, in this case the email, but mutating them would cause my domain events being fired which I wouldn’t like to happen until the new email is valid

So after considering these approaches, I came out with this one, since I am going to implement a CQRS architecture:

class EmailDomainIsAllowedValidator : IDomainInvariantValidator<Customer, ChangeEmailCommand>
{
   public void IsValid(Customer entity, ChangeEmailCommand command)
   {
      if(!command.Email.HasValidDomain())  throw new DomainException(“...”);
   }
}

Well that’s the main idea, the entity is passed to the validator in case we need some value from the entity to perform the validation, the command contains the data coming from the user and since the validators are considered injectable objects they could have external dependencies injected if the validation requires it.

Now the dilemma, I am happy with a design like this because my validation is encapsulated in individual objects which brings many advantages: easy unit test, easy to maintain, domain invariants are explicitly expressed using the Ubiquitous Language, easy to extend, validation logic is centralized and validators can be used together to enforce complex domain rules. And even when I know I am placing the validation of my entities outside of them (You could argue a code smell - Anemic Domain) but I think the trade-off is acceptable

But there is one thing that I have not figured out how to implement it in a clean way. How should I use this components...

Since they will be injected, they won’t fit naturally inside my domain entities, so basically I see two options:

  1. Pass the validators to each method of my entity

  2. Validate my objects externally (from the command handler)

I am not happy with the option 1 so I would explain how I would do it with the option 2

class ChangeEmailCommandHandler : ICommandHandler<ChangeEmailCommand>
{
   // here I would get the validators required for this command injected
   private IEnumerable<IDomainInvariantValidator> validators;
   public void Execute(ChangeEmailCommand command)
   {
      using (var t = this.unitOfWork.BeginTransaction())
      {
         var customer = this.unitOfWork.Get<Customer>(command.CustomerId);
         // here I would validate them, something like this
         this.validators.ForEach(x =. x.IsValid(customer, command));
         // here I know the command is valid
         // the call to ChangeEmail will fire domain events as needed
         customer.ChangeEmail(command.Email);
         t.Commit();
      }
   }
}

Well this is it. Can you give me your thoughts about this or share your experiences with Domain entities validation

EDIT

I think it is not clear from my question, but the real problem is: Hiding the domain rules has serious implications in the future maintainability of the application, and also domain rules change often during the life-cycle of the app. Hence implementing them with this in mind would let us extend them easily. Now imagine in the future a rules engine is implemented, if the rules are encapsulated outside of the domain entities, this change would be easier to implement

I am aware that placing the validation outside of my entities breaks the encapsulation as @jgauffin mentioned in his answer, but I think that the benefits of placing the validation in individual objects is much more substantial than just keeping the encapsulation of an entity. Now I think the encapsulation makes more sense in a traditional n-tier architecture because the entities were used in several places of the domain layer, but in a CQRS architecture, when a command arrives, there will be a command handler accessing an aggregate root and performing operations against the aggregate root only creating a perfect window to place the validation.

I'd like to make a small comparison between the advantages to place validation inside an entity vs placing it in individual objects

  • Validation in Individual objects

    • Pro. Easy to write
    • Pro. Easy to test
    • Pro. It's explicitly expressed
    • Pro. It becomes part of the Domain design, expressed with the current Ubiquitous Language
    • Pro. Since it's now part of the design, it can be modeled using UML diagrams
    • Pro. Extremely easy to maintain
    • Pro. Makes my entities and the validation logic loosely coupled
    • Pro. Easy to extend
    • Pro. Following the SRP
    • Pro. Following the Open/Close principle
    • Pro. Not breaking the law of Demeter (mmm)?
    • Pro. I'is centralized
    • Pro. It could be reusable
    • Pro. If required, external dependencies can be easily injected
    • Pro. If using a plug-in model, new validators can be added just by dropping the new assemblies without the need to re-compile the whole application
    • Pro. Implementing a rules engine would be easier
    • Con. Breaking encapsulation
    • Con. If encapsulation is mandatory, we would have to pass the individual validators to the entity (aggregate) method
  • Validation encapsulated inside the entity

    • Pro. Encapsulated?
    • Pro. Reusable?

I would love to read your thoughts about this

Connotation answered 4/6, 2012 at 9:54 Comment(1)
Most of the items listed as "pros" for placing validation logic in individual objects can also be listed as "pros" for placing validation logic in the entity.Conformist
B
13

I agree with a number of the concepts presented in other responses, but I put them together in my code.

First, I agree that using Value Objects for values that include behavior is a great way to encapsulate common business rules and an e-mail address is a perfect candidate. However, I tend to limit this to rules that are constant and will not change frequently. I'm sure you are looking for a more general approach and e-mail is just an example, so I won't focus on that one use-case.

The key to my approach is recognizing that validation serves different purposes at different locations in an application. Put simply, validate only what is required to ensure that the current operation can execute without unexpected/unintended results. That leads to the question what validation should occur where?

In your example, I would ask myself if the domain entity really cares that the e-mail address conforms to some pattern and other rules or do we simply care that 'email' cannot be null or blank when ChangeEmail is called? If the latter, than a simple check to ensure a value is present is all that is needed in the ChangeEmail method.

In CQRS, all changes that modify the state of the application occur as commands with the implementation in command handlers (as you've shown). I will typically place any 'hooks' into business rules, etc. that validate that the operation MAY be performed in the command handler. I actually follow your approach of injecting validators into the command handler which allows me to extend/replace the rule set without making changes to the handler. These 'dynamic' rules allow me to define the business rules, such as what constitutes a valid e-mail address, before I change the state of the entity - further ensuring it does not go into an invalid state. But 'invalidity' in this case is defined by the business logic and, as you pointed out, is highly volitile.

Having come up through the CSLA ranks, I found this change difficult to adopt because it does seem to break encapsulation. But, I agrue that encapsulation is not broken if you take a step back and ask what role validation truly serves in the model.

I've found these nuances to be very important in keeping my head clear on this subject. There is validation to prevent bad data (eg missing arguments, null values, empty strings, etc) that belongs in the method itself and there is validation to ensure the business rules are enforced. In the case of the former, if the Customer must have an e-mail address, then the only rule I need to be concerned about to prevent my domain object from becoming invalid is to ensure that an e-mail address has been provided to the ChangeEmail method. The other rules are higher level concerns regarding the validity of the value itself and really have no affect on the validity of the domain entity itself.

This has been the source of a lot of 'discussions' with fellow developers but when most take a broader view and investigate the role validation really serves, they tend to see the light.

Finally, there is also a place for UI validation (and by UI I mean whatever serves as the interface to the application be it a screen, service endpoint or whatever). I find it perfectly reasonably to duplicate some of the logic in the UI to provide better interactivity for the user. But it is because this validation serves that single purpose why I allow such duplication. However, using injected validator/specification objects promotes reuse in this way without the negative implications of having these rules defined in multiple locations.

Not sure if that helps or not...

Bellwether answered 11/6, 2012 at 13:31 Comment(2)
" The other rules are higher level concerns regarding the validity of the value itself and really have no affect on the validity of the domain entity itself." - Why are they higher level concerns? Cannot we create a value object from the email address and check the validity of the injected data by a setter? So we can ensure, that every email address is validated against the pattern. Validating against email patterns on a higher abstraction level might lead to code repetition, which can lead to bugs. For example I can forget to add an email pattern validator to the service, etc...Stpeter
"However, I tend to limit this to rules that are constant and will not change frequently." I'd respond by saying that you can have value objects that are local to your aggregate only. And you can have value objects that are "general" (put them in a different folder outside the aggregate for use in any entity). I believe Evans or Vaughn suggest this. You can start by using the general one until you find an entity that needs different validation rules.Pressurecook
O
8

I wouldn't suggest trowing big pieces of code into your domain for validation. We eliminated most of our awkward placed validations by seeing them as a smell of missing concepts in our domain. In your sample code you write I see validation for an e-mail address. A Customer doesn't have anything to do with email validation.

Why not make an ValueObject called Email that does this validation at construct?

My experience is that awkward placed validations are hints to missed concepts in your domain. You can catch them in Validator objects, but I prefer value object because you make the related concept part of your domain.

Organist answered 6/6, 2012 at 6:8 Comment(4)
I wouldn't suggest trowing big pieces of code But the validators are really small and concrete and they follow the SRP. but I prefer value object because you make the related concept part of your domain The validators can be seeing as part of the domain, and they can be modeled in the domain, and in my opinion they make validation explicit, when you place validation inside an entity or a value object, the valdiation is hidden (encapsulated indeed).Connotation
About the value object, it makes sense to me, I would be encapsulating the validation where it really belongs, not in the entity, but I think the problems are the same as placing it in the entity, I mean the advantages I listed in the post, they are the same either the validation is inside the entity or a value object. So specifically, what would be the trade-offs when using validation inside a value object over the trade-offs of placing them in individual objects???Connotation
"My experience is that awkward placed validations are hints to missed concepts in your domain. " - I am not sure of this rule. By the current scenario it works to move the low level validation code to a low level value object. By higher abstraction level validation code it might not work. I need more experience, but thanks the advice.Stpeter
Agree. But just the Value Object is not always enough. Imagine that valid emails should not match with a blocklist of known spam domains, and that these are retrieved from an external lookup service. Then in the Application layer you might have an SpamEmailValidator that's initialized with this service (from the Infrastructure layer). The validator is subsequently passed to the Email Value Object and this value object in turn passed to the Aggregate Root by the command handler. The aggregate can then call Email.IsValid() and be able to raise a domain error, e.g. CustomerEmailInvalid.Toque
K
6

I am at the beginning of a project and I am going to implement my validation outside my domain entities. My domain entities will contain logic to protect any invariants (such as missing arguments, null values, empty strings, collections, etc). But the actual business rules will live in validator classes. I am of the mindset of @SonOfPirate...

I am using FluentValidation that will essentially give me bunch of validators that act on my domain entities: aka, the specification pattern. Also, in accordance with the patterns described in Eric's blue book, I can construct the validators with any data they may need to perform the validations (be it from the database or another repository or service). I would also have the option to inject any dependencies here too. I can also compose and reuse these validators (e.g. an address validator can be reused in both an Employee validator and Company validator). I have a Validator factory that acts as a "service locator":

public class ParticipantService : IParticipantService
{
    public void Save(Participant participant)
    {
        IValidator<Participant> validator = _validatorFactory.GetValidator<Participant>();
        var results = validator.Validate(participant);
            //if the participant is valid, register the participant with the unit of work
            if (results.IsValid)
            {
                if (participant.IsNew)
                {
                    _unitOfWork.RegisterNew<Participant>(participant);
                }
                else if (participant.HasChanged)
                {
                    _unitOfWork.RegisterDirty<Participant>(participant);
                }
            }
            else
            {
                _unitOfWork.RollBack();
                //do some thing here to indicate the errors:generate an exception (or fault) that contains the validation errors. Or return the results
            }
    }

}

And the validator would contain code, something like this:

   public class ParticipantValidator : AbstractValidator<Participant>
    {
        public ParticipantValidator(DateTime today, int ageLimit, List<string> validCompanyCodes, /*any other stuff you need*/)
        {...}

    public void BuildRules()
    {
             RuleFor(participant => participant.DateOfBirth)
                    .NotNull()
                    .LessThan(m_today.AddYears(m_ageLimit*-1))
                    .WithMessage(string.Format("Participant must be older than {0} years of age.", m_ageLimit));

            RuleFor(participant => participant.Address)
                .NotNull()
                .SetValidator(new AddressValidator());

            RuleFor(participant => participant.Email)
                .NotEmpty()
                .EmailAddress();
            ...
}

    }

We have to support more than one type of presentation: websites, winforms and bulk loading of data via services. Under pinning all these are a set of services that expose the functionality of the system in a single and consistent way. We do not use Entity Framework or ORM for reasons that I will not bore you with.

Here is why I like this approach:

  • The business rules that are contained in the validators are totally unit testable.
  • I can compose more complex rules from simpler rules
  • I can use the validators in more than one location in my system (we support websites and Winforms, and services that expose functionality), so if there is a slightly different rule required for a use case in a service that differs from the websites, then I can handle that.
  • All the vaildation is expressed in one location and I can choose how / where to inject and compose this.
Knick answered 12/6, 2012 at 15:5 Comment(1)
With this approach, would you have a lot of pairings? Say EmailAddressValidator with EmailAddressValueObject? What about naming? Perhaps go with the name of the first aggregate it was used in (ie. Users\EmailAddressValidator)? If so I think validators and value objects seem to benefit from being merged. You can have general value objects and value objects specific to a particular aggregate. I'm just thinking here...as I'm new in DDD.Pressurecook
C
5

You put validation in the wrong place.

You should use ValueObjects for such things. Watch this presentation http://www.infoq.com/presentations/Value-Objects-Dan-Bergh-Johnsson It will also teach you about Data as Centers of Gravity.

There also a sample of how to reuse data validation, like for example using static validation methods ala Email.IsValid(string)

Cyrillus answered 6/6, 2012 at 19:44 Comment(3)
thanks a lot Yevhen. As a ddd beginner, your answers are always inspiring.Bennettbenni
You put validation in the wrong place I totally respect your opinion and If you could point me concrete advantages (trade-offs) between placing the validation inside a value object vs placing it in individual objects (as I did at the end of my post) I would appreciate it.Connotation
I agree, it can prevent code duplication from my point of view.Stpeter
M
2

I would not call a class which inherits from EntityBase my domain model since it couples it to your persistence layer. But that's just my opinion.

I would not move the email validation logic from the Customer to anything else to follow the Open/Closed principle. To me, following open/closed would mean that you have the following hierarchy:

public class User
{
    // some basic validation
    public virtual void ChangeEmail(string email);
}

public class Employee : User
{
    // validates internal email
    public override void ChangeEmail(string email);
}

public class Customer : User
{
    // validate external email addresses.
    public override void ChangeEmail(string email);
}

You suggestions moves the control from the domain model to an arbitrary class, hence breaking the encapsulation. I would rather refactor my class (Customer) to comply to the new business rules than doing that.

Use domain events to trigger other parts of the system to get a more loosely coupled architecture, but don't use commands/events to violate the encapsulation.

Exceptions

I just noticed that you throw DomainException. That's a way to generic exception. Why don't you use the argument exceptions or the FormatException? They describe the error much better. And don't forget to include context information helping you to prevent the exception in the future.

Update

Placing the logic outside the class is asking for trouble imho. How do you control which validation rule is used? One part of the code might use SomeVeryOldRule when validating while another using NewAndVeryStrictRule. It might not be on purpose, but it can and will happen when the code base grows.

It sounds like you have already decided to ignore one of the OOP fundamentals (encapsulation). Go ahead and use a generic / external validation framework, but don't say that I didn't warn you ;)

Update2

Thanks for your patience and your answers, and that's the reason why I posted this question, I feel the same an entity should be responsible to guarantee it's in a valid state (and I have done it in previous projects) but the benefits of placing it in individual objects is huge and like I posted there's even a way to use individual objects and keep the encapsulation but personally I am not so happy with design but on the other hand it is not out of the table, consider this ChangeEmail(IEnumerable> validators, string email) I have not thought in detail the imple. though

That allows the programmer to specify any rules, it may or may not be the currently correct business rules. The developer could just write

customer.ChangeEmail(new IValidator<Customer>[] { new NonValidatingRule<Customer>() }, "notAnEmail")

which accepts everything. And the rules have to be specified in every single place where ChangeEmail is being called.

If you want to use a rule engine, create a singleton proxy:

public class Validator
{
    IValidatorEngine _engine;

    public static void Assign(IValidatorEngine engine)
    {
        _engine = engine;
    }

    public static IValidatorEngine Current { get { return _engine; } }
}

.. and use it from within the domain model methods like

public class Customer
{
    public void ChangeEmail(string email)
    {
        var rules = Validator.GetRulesFor<Customer>("ChangeEmail");
        rules.Validate(email);

        // valid
    }

}

The problem with that solution is that it will become a maintenance nightmare since the rule dependencies are hidden. You can never tell if all rules have been specified and working unless you test every domain model method and each rule scenario for every method.

The solution is more flexible but will imho take a lot more time to implement than to refactor the method who's business rules got changed.

Monies answered 4/6, 2012 at 10:16 Comment(16)
EntityBase has nothing to do with persitence. It is a POCO adding common logic to GetHashCode, and Equals basically. I do not agree with the way you model the Open/Close principle. But I totally agree with you about that moving the logic from Customer breaks the encapsulation (I said that in the post), and I am not happy with that but the trade-offs vs placing it outside are bigger and more important from my point of view don't you think? The other approach that I could use is passing the validator objects to my entities methods something like this ChangeEmail(IEnumerable<IValidator> v)Connotation
I think it is not clear from my question, but the real problem is: Hiding the domain rules has serious implications in the future maintainability of the application, and also domain rules change often during the life-cycle of the app. Hence implementing them with this in mind would let us extend them easily. Now imagine in the future a rules engine is implemented, if the rules are encapsulated outside of the domain entities will make this change easier.Connotation
The DomainException is just as an example, there are several specific exceptionsConnotation
But why do you have to know the email business rules outside the method? The user who enters the email should get a hint from the exception messages about what he entered incorrectly. (and I said that your first code sample do not violate OCP other than it do not have the virtual keyword)Monies
hehe That's exactly the point (YOU GOT IT), and I understand (see my edited post) and I agree with you but can you give me some key points or advantages that I will gain encapsulating the validation in an entity? I will update the post to specify key points of placing it outsideConnotation
My last blog post is about encapsulation: blog.gauffin.org/2012/06/protect-your-dataMonies
I understand the importance of encapsulation... what I would like to hear is benefits against placing my validation logic outside of my entities I just edited my post adding some of the advantages of placing the validation in individual objects just from the top of my head, I'm sure there are moreConnotation
Still you are not providing useful info (or at least I do not see any value yet). If you could point out some concrete advantages, that would be great and I would take them into consideration. Placing the logic outside the class is asking for trouble imho on the contrary. As a matter of fact I have had the luck to work on projects placing the validation inside the entities, but there were always problems when trying to use external dependencies to perform the validation or when trying to validate domain graph of objects (recursively).Connotation
Please check this video urgently infoq.com/presentations/Making-Roles-Explicit-Udi-DahanConnotation
If you don't get it you have probably not understood the purpose of encapsulation. There are several articles about that. I'm not going to comment any more.Monies
I understand the purpose but what it seems you do not understand is all the benefit of skipping it in a design like this. Just remember every design decision has trade-offs, our job is to evaluate them and choose the one with less negative implications. What I politely asked you several times was to post some concrete advantages between placing the validation inside an entity vs placing it outside. Your argument in my opinion is based on: follow this rule and do not think the alternativesConnotation
You do not get my point. DataAnnotations etc where created for the very same reason. But nothing other than the class itself can guarantee that it's in a valid state. If you think that that's a sacrifice that you are willing to take, then by all means: Go ahead.Monies
Thanks for your patience and your answers, and that's the reason why I posted this question, I feel the same an entity should be responsible to guarantee it's in a valid state (and I have done it in previous projects) but the benefits of placing it in individual objects is huge and like I posted there's even a way to use individual objects and keep the encapsulation but personally I am not so happy with design but on the other hand it is not out of the table, consider this ChangeEmail(IEnumerable<IValidator<Customer>> validators, string email) I have not thought in detail the imple. thoughConnotation
mmm that's the worst idea. That's the first signal the code is not test-friendly lol? misko.hevery.com/code-reviewers-guideConnotation
@Monies +1, I think it is obvious that breaking encapsulation is "looking for trouble", or from a different perspective it is a sign of code in wrong abstraction level.Stpeter
@Connotation I think you should read Clean Code. Moving validators out of the class will cause code repetition, which will cause hard maintenance, which will use bugs. My experience is that code repetition is a sign of having code in a wrong abstraction level. In the current case the abstraction level is too high for the email pattern validation, so you should move that into the entity or into a value object and encapsulate it.Stpeter
B
2

I cannot say what I did is the perfect thing to do for I am still struggling with this problem myself and fighting one fight at a time. But I have been doing so far the following thing :

I have basic classes for encapsulating validation :

public interface ISpecification<TEntity> where TEntity : class, IAggregate
    {
        bool IsSatisfiedBy(TEntity entity);
    }

internal class AndSpecification<TEntity> : ISpecification<TEntity> where TEntity: class, IAggregate
    {
        private ISpecification<TEntity> Spec1;
        private ISpecification<TEntity> Spec2;

        internal AndSpecification(ISpecification<TEntity> s1, ISpecification<TEntity> s2)
        {
            Spec1 = s1;
            Spec2 = s2;
        }

        public bool IsSatisfiedBy(TEntity candidate)
        {
            return Spec1.IsSatisfiedBy(candidate) && Spec2.IsSatisfiedBy(candidate);
        }


    }

    internal class OrSpecification<TEntity> : ISpecification<TEntity> where TEntity : class, IAggregate
    {
        private ISpecification<TEntity> Spec1;
        private ISpecification<TEntity> Spec2;

        internal OrSpecification(ISpecification<TEntity> s1, ISpecification<TEntity> s2)
        {
            Spec1 = s1;
            Spec2 = s2;
        }

        public bool IsSatisfiedBy(TEntity candidate)
        {
            return Spec1.IsSatisfiedBy(candidate) || Spec2.IsSatisfiedBy(candidate);
        }
    }

    internal class NotSpecification<TEntity> : ISpecification<TEntity> where TEntity : class, IAggregate
    {
        private ISpecification<TEntity> Wrapped;

        internal NotSpecification(ISpecification<TEntity> x)
        {
            Wrapped = x;
        }

        public bool IsSatisfiedBy(TEntity candidate)
        {
            return !Wrapped.IsSatisfiedBy(candidate);
        }
    }

    public static class SpecsExtensionMethods
    {
        public static ISpecification<TEntity> And<TEntity>(this ISpecification<TEntity> s1, ISpecification<TEntity> s2) where TEntity : class, IAggregate
        {
            return new AndSpecification<TEntity>(s1, s2);
        }

        public static ISpecification<TEntity> Or<TEntity>(this ISpecification<TEntity> s1, ISpecification<TEntity> s2) where TEntity : class, IAggregate
        {
            return new OrSpecification<TEntity>(s1, s2);
        }

        public static ISpecification<TEntity> Not<TEntity>(this ISpecification<TEntity> s) where TEntity : class, IAggregate
        {
            return new NotSpecification<TEntity>(s);
        }
    }

and to use it, I do the following :

command handler :

 public class MyCommandHandler :  CommandHandler<MyCommand>
{
  public override CommandValidation Execute(MyCommand cmd)
        {
            Contract.Requires<ArgumentNullException>(cmd != null);

           var existingAR= Repository.GetById<MyAggregate>(cmd.Id);

            if (existingIntervento.IsNull())
                throw new HandlerForDomainEventNotFoundException();

            existingIntervento.DoStuff(cmd.Id
                                , cmd.Date
                                ...
                                );


            Repository.Save(existingIntervento, cmd.GetCommitId());

            return existingIntervento.CommandValidationMessages;
        }

the aggregate :

 public void DoStuff(Guid id, DateTime dateX,DateTime start, DateTime end, ...)
        {
            var is_date_valid = new Is_dateX_valid(dateX);
            var has_start_date_greater_than_end_date = new Has_start_date_greater_than_end_date(start, end);

        ISpecification<MyAggregate> specs = is_date_valid .And(has_start_date_greater_than_end_date );

        if (specs.IsSatisfiedBy(this))
        {
            var evt = new AgregateStuffed()
            {
                Id = id
                , DateX = dateX

                , End = end        
                , Start = start
                , ...
            };
            RaiseEvent(evt);
        }
    }

the specification is now embedded in these two classes :

public class Is_dateX_valid : ISpecification<MyAggregate>
    {
        private readonly DateTime _dateX;

        public Is_data_consuntivazione_valid(DateTime dateX)
        {
            Contract.Requires<ArgumentNullException>(dateX== DateTime.MinValue);

            _dateX= dateX;
        }

        public bool IsSatisfiedBy(MyAggregate i)
        {
            if (_dateX> DateTime.Now)
            {
                i.CommandValidationMessages.Add(new ValidationMessage("datex greater than now"));
                return false;
            }

            return true;
        }
    }

    public class Has_start_date_greater_than_end_date : ISpecification<MyAggregate>
    {
        private readonly DateTime _start;
        private readonly DateTime _end;

        public Has_start_date_greater_than_end_date(DateTime start, DateTime end)
        {
            Contract.Requires<ArgumentNullException>(start == DateTime.MinValue);
            Contract.Requires<ArgumentNullException>(start == DateTime.MinValue);

            _start = start;
            _end = end;
        }

        public bool IsSatisfiedBy(MyAggregate i)
        {
            if (_start > _end)
            {
                i.CommandValidationMessages.Add(new ValidationMessage(start date greater then end date"));
                return false;
            }

            return true;
        }
    }

This allows me to reuse some validations for different aggregate and it is easy to test. If you see any flows in it. I would be real happy to discuss it.

yours,

Bennettbenni answered 4/6, 2012 at 13:42 Comment(3)
It looks like your process is almost the process I presented which makes me think I am not alone with this tendency, the only difference is that you encapsulated the rules inside the method which at first glance looks good, but I have a question for you, are you heavily writing unit tests for you code? because since you are creating the objects inside you cannot test in isolation the aggregate root method. As another side effect, if the validator requires an external dependency, you would have to use the Service Locator anti-pattern, and to test that you would end up with integration testsConnotation
Your implementation of the specification pattern, actually solves the problem to have to mutate first the entity in order to validate it I will evaluate this kind of design. Just from the top of my head, I'm not sure if I would use a constructor to pass the values, because I intended to have a flexible design where I can inject dependencies to the validators. Check this link based on Misko Hevery loosecouplings.com/2011/01/…Connotation
So far I was not testing in isolation my aggregate root method. It's a flaw I discover while running through the "discussion" you had with @jgauffin. I have a class per method IsSatisfiedBy(MyAggregate i) basically, so if I need external dependencies. These would come from Ctor injection. Actually, to me , so far at least, even arguments coming from the command are external dependencies. But I might change in the future. I will definitely be looking into this validation injection to decouple my aggregate root method from the validation. Have a nice day...Bennettbenni
S
1

From my OO experience (I am not a DDD expert) moving your code from the entity to a higher abstraction level (into a command handler) will cause code duplication. This is because every time a command handler gets an email address, it has to instantiate email validation rules. This kind of code will rot after a while, and it will smell very badly. In the current example it might not, if you don't have another command which changes the email address, but in other situations it surely will...

If you don't want to move the rules back to a lower abstraction level, like the entity or an email value object, then I strongly suggest you to reduce the pain by grouping the rules. So in your email example the following 3 rules:

  if(string.IsNullOrWhitespace(email))   throw new DomainException(“...”);
  if(!email.IsEmail())  throw new DomainException();
  if(email.Contains(“@mailinator.com”))  throw new DomainException();

can be part of an EmailValidationRule group which you can reuse easier.

From my point of view there is no explicit answer to the question where to put the validation logic. It can be part of every object depending on the abstraction level. In you current case the formal checking of the email address can be part of an EmailValueObject and the mailinator rule can be part of a higher abstraction level concept in which you state that your user cannot have an email address pointing on that domain. So for example if somebody wants to contact with your user without registration, then you can check her email against formal validation, but you don't have to check her email against the mailinator rule. And so on...

So I completely agree with @pjvds who claimed that this kind of awkward placed validation is a sign of a bad design. I don't think you will have any gain by breaking encapsulation, but it's your choice and it will be your pain.

Stpeter answered 25/9, 2014 at 3:2 Comment(0)
D
0

The validation in your example is validation of a value object, not an entity (or aggregate root).

I would separate the validation into distinct areas.

  1. Validate internal characteristics of the Email value object internally.

I adhere to the rule that aggregates should never be in an invalid state. I extend this principal to value objects where practical.

Use createNew() to instantiate an email from user input. This forces it to be valid according to your current rules (the "[email protected]" format, for example).

Use createExisting() to instantiate an email from persistent storage. This performs no validation, which is important - you don't want an exception to be thrown for a stored email that was valid yesterday but invalid today.

class Email
{
    private String value_;

    // Error codes
    const Error E_LENGTH = "An email address must be at least 3 characters long.";
    const Error E_FORMAT = "An email address must be in the '[email protected]' format.";

    // Private constructor, forcing the use of factory functions
    private Email(String value)
    {
        this.value_ = value;
    }

    // Factory functions
    static public Email createNew(String value)
    {
        validateLength(value, E_LENGTH);
        validateFormat(value, E_FORMAT);
    }

    static public Email createExisting(String value)
    {
        return new Email(value);
    }

    // Static validation methods
    static public void validateLength(String value, Error error = E_LENGTH)
    {
        if (value.length() < 3)
        {
            throw new DomainException(error);
        }
    }

    static public void validateFormat(String value, Error error = E_FORMAT)
    {
        if (/* regular expression fails */)
        {
            throw new DomainException(error);
        }
    }

}
  1. Validate "external" characteristics of the Email value object externally, e.g., in a service.

    class EmailDnsValidator implements IEmailValidator
    {
        const E_MX_MISSING = "The domain of your email address does not have an MX record.";
    
        private DnsProvider dnsProvider_;
    
        EmailDnsValidator(DnsProvider dnsProvider)
        {
            dnsProvider_ = dnsProvider;
        }
    
        public void validate(String value, Error error = E_MX_MISSING)
        {
            if (!dnsProvider_.hasMxRecord(/* domain part of email address */))
            {
                throw new DomainException(error);
            }
        }
    }
    
    class EmailDomainBlacklistValidator implements IEmailValidator
    {
        const Error E_DOMAIN_FORBIDDEN = "The domain of your email address is blacklisted.";
    
        public void validate(String value, Error error = E_DOMAIN_FORBIDDEN)
        {
            if (/* domain of value is on the blacklist */))
            {
                throw new DomainException(error);
            }
        }
    }
    

Advantages:

  • Use of the createNew() and createExisting() factory functions allow control over internal validation.

  • It is possible to "opt out" of certain validation routines, e.g., skip the length check, using the validation methods directly.

  • It is also possible to "opt out" of external validation (DNS MX records and domain blacklisting). E.g., a project I worked on initially validated the existance of MX records for a domain, but eventually removed this because of the number of customers using "dynamic IP" type solutions.

  • It is easy to query your persistent store for email addresses that do not fit the current validation rules, but running a simple query and treating each email as "new" rather than "existing" - if an exception is thrown, there's a problem. From there you can issue, for example, a FlagCustomerAsHavingABadEmail command, using the exception error message as guidance for the user when they see the message.

  • Allowing the programmer to supply the error code provides flexibility. For example, when sending a UpdateEmailAddress command, the error of "Your email address must be at least 3 characters long" is self explanatory. However, when updating multiple email addresses (home and work), the above error message does not indicate WHICH email was wrong. Supplying the error code/message allows you to provide richer feedback to the end user.

Dentifrice answered 20/5, 2016 at 4:46 Comment(0)
G
0

I wrote a blog post on this topic a while back. The premise of the post was that there are different types of validation. I called them Superficial Validation and Domain Based Command Validation.

This simple version is this. Validating things like 'is it a number' or 'email address' are more often than not just superficial. These can be done before the command reaches the domain entities.

However, where the validation is more tied to the domain then it's right place is in the domain. For example, maybe you have some rules about the weight and type of cargo a certain lorry can take. This sounds much more like domain logic.

Then you have the hybrid types. Things like set based validation. These need to happen before the command is issued or injected into the domain (try to avoid that if at all possible - limiting dependencies is a good thing).

Anyway, you can read the full post here: How To Validate Commands in a CQRS Application

Gracia answered 17/2, 2017 at 9:56 Comment(0)
F
0

I'm still experimenting with this concept but you can try Decorators. If you use SimpleInjector you can easily inject your own validation classes that run ahead of your command handler. Then the command can assume it is valid if it got that far. However, This means all validation should be done on the command and not the entities. The entities won't go into an invalid state. But each command must implement its own validation fully so similar commands may have duplication of rules but you could either abstract common rules to share or treat different commands as truly separate.

Felicidad answered 2/7, 2017 at 12:37 Comment(0)
S
0

My second opinion after 5 years still that the first approach is ok. But if you insist, then instead of injecting the entity into the validator, I would rather inject the validator into the entity.

class Customer : EntityBase<Customer>
{
   public void ChangeEmail(string email)
   {
      ValidationResult result = validator.validateEmail(email);
      if (result.isFailure())
         throw new ValidationException(result);
      /*
                ...
      */
   }
}

I found approaches like this a lot better by all my frameworks or attempts to write a framework. This way you can deliver the details of the failure out of the domain and send it to the presentation. Another thing that many times a validator fails because of multiple reasons and the users need to know all the reasons, not just the first reason. A typical example is something like the new password must contain big and small letters, digits, special characters, must have a certain length, cannot be the same as the previous one, etc. It can be really annoying to try over multiple times correct all of these one by one. As of the validation rules, there can be hard rules, e.g. we need a string as password and softer ones, e.g. the password must be at least 8 characters long. These latter ones can change depending on the security configuration, so better to inject them. So in the domain I would rather define a PasswordValidator class for it or if I don't care about the implementation details, then an PasswordValidator interface and implement it in infrastructure. With proper automated testing the latter can be just as good if you use an external validation framework or library for it.

Stpeter answered 9/3, 2023 at 20:36 Comment(0)
P
-4

You can use a message based solution with Domain Events as explained here.

Exceptions are not the right method for all validation errors, is not said that a not valid entity is an exceptional case.

If the validation is not trivial, the logic to validate the aggregate can be executed directly on the server and while you are trying to set new input you can raise a Domain Event to tell to the user (or the application that is using your domain) why the input is not correct.

Pleuro answered 4/6, 2012 at 10:6 Comment(5)
According to Martin Fowler "The essence of a Domain Event is that you use it to capture things that can trigger a change to the state of the application you are developing. These event objects are then processed to cause changes to the system, and stored to provide an Audit Log". I DO use domain events in this contextConnotation
According to wikipedia "anomalous or exceptional situations requiring special processing – often changing the normal flow of program execution". Somebody says that when you use the word when, there, there is a Domain Event. So if the domain expert says: "when the customer email is not valid do..." there is a domain event.Pleuro
A domain entity should always be in a consistent state. Thus trying to specify data which is not valid is exceptional.Monies
The exceptions should be used only if you do not know how to solve the problem in a certain context, a validation error is not the case. If the email is wrong, yes, the validation at the level of presentation and/or service layers did not work, but it is easy to re-ask to the user to enter a valid address, so the workflow is not compromised.Pleuro
Agreed, but that is the role of UI validation and touches on the fact that there should be validation in each layer focused on what purpose validation serves in each. For example, UI validation is used to provide interactivity and (hopefully) prevent bad data being submitted to the domain. In the domain layer, validation is used to prevent domain entities from entering an invalid state. I agree that exceptions are appropriate in the domain layer. If you don't want the exception to occur, implement UI validation to help the 'user' provide the correct data.Bellwether

© 2022 - 2025 — McMap. All rights reserved.