views:

519

answers:

8

This question is language agnostic but I am a C# guy so I use the term POCO to mean an object that only preforms data storage, usually using getter and setter fields.

I just reworked my Domain Model to be super-duper POCO and am left with a couple of concerns regarding how to ensure that the property values make sense witin the domain.

For example, the EndDate of a Service should not exceed the EndDate of the Contract that Service is under. However, it seems like a violation of SOLID to put the check into the Service.EndDate setter, not to mention that as the number of validations that need to be done grows my POCO classes will become cluttered.

I have some solutions (will post in answers), but they have their disadvantages and am wondering what are some favorite approaches to solving this dilemma?

A: 

I think that would probably be the best place for the logic, actually, but that's just me. You could have some kind of IsValid method that checks all of the conditions too and returns true/false, maybe some kind of ErrorMessages collection but that's an iffy topic since the error messages aren't really a part of the Domain Model. I'm a little biased as I've done some work with RoR and that's essentially what its models do.

Wayne M
SRP - is your model responsible for representing a real world object or for validating input? Gotta be Ruthless in this
George Mauer
+2  A: 

I always hear people argument for a "Validate" or "IsValid" method.

Personally I think this may work, but with most DDD projects you usually end up with multiple validations that are allowable depending on the specific state of the object.

So I prefer "IsValidForNewContract", "IsValidForTermination" or similar, because I believe most projects end up with multiple such validators/states per class. That also means I get no interface, but I can write aggregated validators that read very well reflect the business conditions I am asserting.

I really do believe the generic solutions in this case very often take focus away from what's important - what the code is doing - for a very minor gain in technical elegance (the interface, delegate or whatever). Just vote me down for it ;)

krosenvold
+1  A: 

One solution is to have each object's DataAccessObject take a list of Validators. When Save is called it preforms a check against each validator:

public class ServiceEndDateValidator : IValidator<Service> {
  public void Check(Service s) {
    if(s.EndDate > s.Contract.EndDate)
      throw new InvalidOperationException();
  }
}

public class ServiceDao : IDao<Service> {
  IValidator<Service> _validators;
  public ServiceDao(IEnumerable<IValidator<Service>> validators) {_validators = validators;}
  public void Save(Service s) {
    foreach(var v in _validators)
      v.Check(service);
    // Go on to save
  }
}

The benefit, is very clear SoC, the disadvantage is that we don't get the check until Save() is called.

George Mauer
A: 

Another possibility is to have each of my classes implement

public interface Validatable<T> {
  public event Action<T> RequiresValidation;
}

And have each setter for each class raise the event before setting (maybe I could achieve this via attributes).

The advantage is real-time validation checking. But messier code and it is unclear who should be doing the attaching.

George Mauer
+2  A: 

I think you're starting off with a bad assumption, ie, that you should have objects that do nothing but store data, and have no methods but accessors. The whole point of having objects is to encapsulate data and behaviors. If you have a thing that's just, basically, a struct, what behaviors are you encapsulating?

Charlie Martin
Right, these objects do not encapsulate behaviors. That's the whole point. They represent my domain. That is it. Behavior is provided elsewhere.
George Mauer
Your domain has no behavior?
Charlie Martin
The domain Models have no behavior. behavior is attached to them separately. Services do stuff using the models. At least that's my read on the whole DDD thing.
George Mauer
The design you are describing is referred to as an "Anemic Domain Model". Domain-driven design could be said to be a specific application of Object-oriented design which prescribes the exact opposite which is that an object should encapsulate both the data and behavior for that which it is modeling.
Derek Greer
+1  A: 

In the past I have usually delegated validation to a service unto its own, such as a ValidationService. This in principle still ad hears to the philosophy of DDD.

Internally this would contain a collection of Validators and a very simple set of public methods such as Validate() which could return a collection of error object.

Very simply, something like this in C#

public class ValidationService<T>
{
  private IList<IValidator> _validators;

  public IList<Error> Validate(T objectToValidate)
  {
    foreach(IValidator validator in _validators)
    {
      yield return validator.Validate(objectToValidate);
    }
  }
}

Validators could either be added within a default constructor or injected via some other class such as a ValidationServiceFactory.

Xian
Wouldnt that create parallel hierarchies http://stackoverflow.com/questions/778449/code-smell-or-not-validators-and-models-share-same-kind-of-hiereachy
Surya
Surya, could you explain what you mean by this? I will try to explain further...
Xian
A: 

Here's another possibility. Validation is done through a proxy or decorator on the Domain object:

public class ServiceValidationProxy : Service {
  public override DateTime EndDate {
    get {return EndDate;}
    set {
      if(value > Contract.EndDate)
        throw new InvalidOperationexception();
      base.EndDate = value;
    }
  }
}

Advantage: Instant validation. Can easily be configured via an IoC.

Disadvantage: If a proxy, validated properties must be virtual, if a decorator all domain models must be interface-based. The validation classes will end up a bit heavyweight - proxys have to inherit the class and decorators have to implement all the methods. Naming and organization might get confusing.

George Mauer
+1  A: 

A colleague of mine came up with an idea that worked out pretty well. We never came up with a great name for it but we called it Inspector/Judge.

The Inspector would look at an object and tell you all of the rules it violated. The Judge would decide what to do about it. This separation let us do a couple of things. It let us put all the rules in one place (Inspector) but we could have multiple Judges and choose the Judge by the context.

One example of the use of multiple Judges revolves around the rule that said a Customer must have an Address. This was a standard three tier app. In the UI tier the Judge would produce something that the UI could use to indicate the fields that had to be filled in. The UI Judge did not throw exceptions. In the service layer there was another Judge. If it found a Customer without an Address during Save it would throw an exception. At that point you really have to stop things from proceeding.

We also had Judges that were more strict as the state of the objects changed. It was an insurance application and during the Quoting process a Policy was allowed to be saved in an incomplete state. But once that Policy was ready to be made Active a lot of things had to be set. So the Quoting Judge on the service side was not as strict as the Activation Judge. Yet the rules used in the Inspector were still the same so you could still tell what wasn't complete even if you decided not to do anything about it.

Mike Two