15
May
09

The ‘Always Valid Entity’ is not a fallacy

I had to comment on Jeffrey Palermo’s recent post entitled ‘The fallacy of the always-valid entity’ as I both disagreed with what he was suggesting and wonder if he has missed the point. I thought I’d follow up here with an example that demonstrates how I implement an always valid entity. Many other comments on the post allude to similar approaches also. If you haven’t already, read Jeffrey’s post before reading on.

Jeffrey’s UserProfile class initially throws exceptions in property setters if null values are supplied. These are invariants. I think he’s arguing against this approach. He then evolves the example to present a validation framework that allows a collection of rules to be asserted against an instance of the entity and reports back failed rules.  The rules are intended to be context specific validations, but the context is missing (at least from the example given).

He additionally talks about legacy data and the need to allow for invalid entities for unspecified reasons. He concludes with

“It is futile to attempt to keep entities always-valid.  Let bad things happen to them, and then validate”.

No! I disagree.

If we can’t know an entity is valid anywhere we use it then we can’t afford to trust it. We end up with code where, before we use an entity, we go and check that it is in a suitable state for us. These ‘entities’ are just data structures. They are missing behaviour that enforces internal consistency.

So, how can we build entities in C# that are always valid?

  1. No public property setters. This stops the entity being used as a data structure. It is no longer possible to break the internal state of an entity by abusing setters.
  2. The instance constructor leaves the entity in a valid initial state. It sets sensible defaults for fields, it takes parameters to override defaults and  other parameters to provide values for fields with no sensible default.
  3. Entities are updated by a context-specific ‘command’ method that acts atomically on the instance.

Let’s rework Jeffrey’s UserProfile class to make it an always valid entity, assuming that:

  • The user’s Name must not be empty,
  • The Gender can be one of male, female or unknown.
  • The JoinedDate cannot be null, but can (for now) contain any valid date. You might argue that future dates should be invalid or that the JoinedDate be optional—let’s just ignore this at the moment; is is immaterial for this example.
  • The LastLogin must not be earlier than the JoinedDate.
    public enum Gender
    {
        Unknown = 0,
        Male,
        Female
    }
 
    public class User
    {
        private string name;
 
        public string Name
        {
            get
            {
                return name;
            }
            private set
            {
                if (string.IsNullOrEmpty(value))
                    throw new ArgumentNullException("Name");
 
                name = value;
            }
        }
 
        public Gender Gender { get; private set; }
        public DateTime JoinedDate { get; private set; }
        public DateTime? LastLogin { get; private set; }
 
        public User(string name, Gender gender, DateTime joinedDate)
        {
            Name = name;
            Gender = gender;
            JoinedDate = joinedDate;
        }
 
        public void UpdateProfile(string name, Gender gender)
        {
            Name = name;
            Gender = gender;
        }
 
        public void RecordLogin(DateTime loginTime)
        {
            if (loginTime < JoinedDate)
                throw new InvalidOperationException("loginTime cannot be earlier than JoinedDate");
 
            LastLogin = loginTime;
        }
    }

Whilst I personally wouldn’t want this code in production, lets look at what it has achieved.

  • Gender is an enumeration. This restricts us to valid values at compile time. However, we explicitly recognise a business requirement that the gender may not be known, rather than allow an indeterminate null state.
  • I prefer the entity name User rather then UserProfile. We are modeling a domain with Users. A user’s profile is the properties of the User entity. UserProfile screams data structure.
  • I’ve opted for automatic properties with private setters for most properties. This means the presentation layer can read my entity to create a View Model or for direct binding, but updates through properties are not possible.
  • Where I have an invariant I wish to enforce, I’ve opted to use the private property setter to enforce this. This is a compromise and we must trust our developers not to short-circuit the setter, either by malice or ignorance. This is a pretty weak form of validation (but good enough for this example). Bear with me, I’ll blog on this shortly.
  • ‘Command’ methods update the entity in a controlled manner. They return void. They have atomic behaviour, by which I mean a logical update is made in one call to the instance.
    • The business has asked that the user can update their profile. The name must not be empty.
    • The business also wants to record the last login time for users. Note that we aren’t using DateTime.Now here, as this has two shortcomings: it hurts testability and explicitly ties the time of the execution of the RecordLogin method to the time of the executing server. RecordLogin might be at the end of an message queue that processed the message minutes after the login actually occurs.
  • The constructor and the UpdateProfile method both use the Name setter and therefore the non-empty name invariant is enforced.
  • Note that users of NHibernate or other ORM frameworks might require a default constructor. If so make the accessability as restrictive as possible (that’s ‘protected’ for NH).
  • We can use a validation framework that implements a notify pattern (as in Jeffrey’s example) if we wish. I kept it simple for this example.

Given the rules above, it is not possible to get this entity into an invalid state. As for bulk loads and legacy data, this entity will insist that the external data is correct. Use a data cleansing tool to make sure the data meets your domain models requirements.

In my next post I’ll look at how to improve this code further through the use of value objects.
kick it on DotNetKicks.com

About these ads

2 Responses to “The ‘Always Valid Entity’ is not a fallacy”


  1. May 18, 2009 at 11:13 pm

    Good one,
    “Whilst I personally wouldn’t want this code in production”
    Um….
    Can you explain how this User class will look like in real world? What would you do differently so that this code is production ready?
    -N

  2. 2 andyhitchman
    May 19, 2009 at 10:12 am

    @Mr.N
    The validation is particularly rough and ready. Additionally there potential confusion between the private setter and the field for the name. I use Fluent.Validation (http://fluentvalidation.codeplex.com/) to define business rules and invariants.


Comments are currently closed.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: