Why not just do data driven status changes?

July 23 2011

A good programmer friend of mine posed this question to me after reading my last two posts on this topic.  I’m not sure what he means exactly (I don’t want to second guess what he means), so while I wait for his explanation I thought I’d show a version of how status changes are typically managed by people not understanding patterns, usually junior devs, or those coming from a procedural background.

Typically there would be what we call anaemic domain entities, where the domain entity is essentially a DTO (Data Transfer Object), all properties and no behaviour.  Updating all properties are done from either the UI or the database and procedural code, often in an event handler such as a button click event will update the DTO before it’s persisted.

Here is what such an ‘entity’ would look like.

namespace WorkflowTest
{
    public class Document
    {        
        public string PropertyOne { get; set; }

        public string PropertyTwo { get; set; }

        public string PropertyThree { get; set; }
                
        public string PropertyFour { get; set; }
        
        public int Status { get; set; }
    }
}

Hopefully it is immediately apparent that while an entity should always know it’s status, this entity relies entirely on calling code to understand when it’s state changes.   This means that anywhere this entity is updated we need to duplicate the state change check code prior to assigning to the value to the entity. Even if we assume data binding we still need to repeat this check in every place.  We could refactor to a method, like GetStatus and pass in the Document instance had have it return or set the Status in there.  The GetStatus method would essentially be the same implementation as the private CheckStatus method on my first WorkflowDocument class, this method:

private void CheckStatus()
{
    // Rules for each state change are contained here.
    // This is messy and should be refactored into Status objects.
    if (Status == 0 && !string.IsNullOrEmpty(PropertyOne)) {
        Status = 1;
    }
     
    if (Status == 1 && (!string.IsNullOrEmpty(PropertyTwo) && !string.IsNullOrEmpty(PropertyThree)))
    {
        Status = 2;
    }
     
    if (Status == 2 && (!string.IsNullOrEmpty(PropertyFour)))
    {
        Status = 3;
    }

    if (Status == 3 && string.IsNullOrEmpty(PropertyFour)) {
        Status = 2;
    }
}

 

And we’re back where we started, except for having a method floating around in what will probably be a static helper class.  Bad.  If you remember back to the first post in this series, one of the benefits of the state pattern was reducing the complexity and readability problems of having ALL of your state change logic in this one method.  While the above is fairly simple, where state transitions are more complex, such as can go from one state to many others in a variety of conditions, or when there are many many states, this method would become unwieldy and large. Larger than a single method should be, and really, because the each transition is dependant only on a particular state, not on the entire object in any state, the SRP (Single Responsibilty Pattern) says we should move the  logic for each state transition to separate and individual classes, as in the State Pattern.

We would more than likely still need to store state in the database, particularly for reporting purposes, where  something like Crystal Report may talk directly to the database.  That though is a problem for the persistence strategy.

Post a comment

comments powered by Disqus