Search code examples
oopdomain-driven-designinvariants

Always Valid Entities


I'm interested to see how supporters of the "Always-Valid" entity approach (vs isValid method later) would suggest modelling a object with collections. I really like the idea behind this approach, but I am having difficulty with implementing it as my objects get a bit more complex. I'm wondering, do I need to force users to only use one update method, with all fields specified?

In example:

public Meeting
{
   public string Name {get; protected set;}        -- must have
   public DateTime Time {get; protected set;}      -- must have
   public IWine Wine {get; protected set;}         -- optional
   public string Notneeded2 {get; protected set;}  -- optional
   public string Notneeded3 {get; protected set;}  -- optional
   public string Notneeded4 {get; protected set;}  -- optional
   public string Notneeded5 {get; protected set;}  -- optional
   public string Notneeded6 {get; protected set;}  -- optional

   public IUser Chair {get; protected set;}         --must have 
   public List<IUsers> Users {get; protected set;}  --must have
   public bool isBoardRelated {get; protected set;}  --must have
   public List<IBoardUsers> {get; protected set;}   -- if isBoardRelated, then must have

   private void CheckInvariants()
   {
       if (blah == null &&....etc)
       {
             throw new ModelInvariantCheckException("Catch me and cry");
        }
    }

}

So, should the following present the user with only one constructor and one update method with all fields specified? Or should multiple constructors be used? Would allowing certain properties (optionals) to have public setters make things inconsistent?

Or do people prefer using an isValid method that must be called later?

I must say, my preference is to have invariant checks as it feels safer, but having to add every property to both constructor and update method makes things a lot slower when calling between layers, and even object setup. Collections consisting of always-valid classes exacerbates this.


Solution

  • When practicing Domain Driven Design, you want to avoid a big Update method. Update methods don't capture the language of your domain - they bring database language into your domain. Try to make the language explicit, and you will be able to extract value objects, invariants and intent-revealing methods that mutate the state of your entity.

    Maybe you can find some inspiration here.