If you haven't already read it, take a moment to read the last article. It provides the background required for this posting to make sense.
OK, so lets say that an object can have n-states. In each state it has 0..n valid attributes and 0..n valid methods. We could actually simplify this model by removing the concept of attributes. Assuming you use getter and setter methods to access all attributes, we could just say that any given state has 0..n valid methods as if an attribute wasn't valid then the get#AttributeName#() method just wouldn't be available and if the attribute couldn't be changed within that state then the set#AttributeName#() method wouldn't be available. I'm actually going to keep the distinction between actions and attributes as I think I'd rather annotate my attributes with the states in which they are available rather than obsfucating that intent by mixing it up with the common implementation decision to have getter are setter methods which is not the universal solution to the problem.
Another element of state relates to validations. The validations to be applied to both an object and attributes of an object vary by state. A visitor may not need any validation at all, but to transition to a registered user they will at the very least have to have a valid email address (or username) and password.
Should we associate validations to a state or to a state transition? On the whole I would say that validations should be associated to a given state and should be checked automatically when making any transition to that state. In that way, if there were three different ways of transitioning to a given state, all three would run the same validations which is appropriate as it is the attainment of the state itself that demands the preconditions – not the particular path used to attain that state.
So, We have an object with a universe of attributes, validations and actions. It has n-states and each state has a subset of the attributes, validations and actions. Certain actions – if successfully performed, should also change the state of the object. So, what are some of the ways that we could capture these business rules?
Generally there are two ways we could go about documenting this information – whether we use an in-language approach such as annotations or an external solution such as a database or an XML configuration file. In either case we could either document the states associated to each element or the elements associated to each state (where an element is an attribute, validation or action).
I think that on the whole, it makes more sense for a state to know about its constituent elements rather than for an element to know about its valid states. I don't think a FirstName attribute should know what states it is available in, but I think that a Registered state should know that it provides access to the FirstName attribute. I can see this being a little bit of work when adding new attributes or methods that are available in lots of states, so I'll play with it and see how it works in practice.
States vs. Roles
One concern I have is where an object can have multiple roles and each role has its own validations. The distinction for me between a state and a role is that an object could simultaneous have multiple roles but only one state. This of course leads to the question of whether we should just model an object in terms of roles where state is just a special case of roles where the number of roles = 1.
I'm really excited about being able to declaratively describe more of the intent of my applications and to get rid of the informal documentation, boilerplate coding and conventions which are often used to capture these kinds of business rules.
I'm still not convinced as to whether I should be modeling roles or states. And while I have a strong intuition that it's the roles or states that should know about their constituent elements rather than the other way around, I have a feeling I'm still going to have to add some enhancements to that basic approach to come up with a solution that is reasonably DRY for complex objects with lots of states/roles and elements.
What do you think? Have you tried something like this before? Do you think it would be valuable? Would you use the concept of roles or states and how would you encode your intent?
Any input appreciated!