Last post I was thinking about change and how one plans for change in the life of an application. I became particularly interested in this after hearing from customers about the pain of versioning and how little we help them with this in the platform. One trend that makes this even more painful is the idea that the platform can manage state for your application automatically. The prime example of this is how Windows Workflow (WF) can automatically persist a workflow.
The vast majority of applications manage their own state. In a typical N-Tier architecture, applications have a data layer that takes on this responsibility and provides a layer of insulation against change. If the mean old DBA decides to change the database in some way, our friend the data layer can absorb the impact of such changes without them rippling throughout the entire application. In fact the idea of every external interaction having a layer between it and the rest of the application is such a good idea that it is often used for services as well. On the sending side a service agent can provide a place to contain logic that is needed for invoking an external service. On the receiving end a service facade can be used to deal with boundary issues.
There are some principles we need to keep in mind about Behavior and State when thinking about change over time. While not absolutes, I believe these principles to be true in general
Behavior and State are linked temporarily
You create an object, it has behavior which was built at compile time. State on the other hand is built up at runtime. It is either collected from a user, function calls or read from a durable store. Eventually your object has both behavior and state that is required to fulfill it’s task. For some moment in time the two state and behavior are bound together. Your application is designed to restore the world to this moment in time at some future point as well.
State lives longer than Behavior
The business process that your object supports outlives your object in time. The time scale of the real world is much slower than the machine. Instead of micro or milliseconds we operate on the scale of minutes, hours, days, weeks, months. The state that helps us get our work done is mostly kept in durable storage so we can recall it, act on it and store it again.
Behavior Changes More Often Than State (schema)
Yes, state changes, but the schema of state changes less often than behavior. You fix a bug, you modify a business rule, these changes occur with greater frequency than changes like adding a field to a table.
Behavior Changes often require State Migration
You changed a business rule. Does this change affect state? Possibly. You might need to run the business rule again on orders placed in the last week. You added a new field, in the database this field is now blank. You might now need to run a process that will lookup or calculate a value for this new field in order to make the record valid.
The Place of Vulnerability
If there is one place in our application where we will feel pain around versioning it is in the place where the new behavior encounters the old state. Whenever we have code that attempts to read state we must have a plan for what to do when we face this situation. Increasingly the trend has been to want platform infrastructure to manage this for us automatically. The typical way this is done in the past was to serialize the state to a stream of some kind.
While this sounds great on the surface, problems occur when the new behavior encounters this old state. Usually at this point de-serialization fails because it doesn’t know what to do with this old state. Worse yet, if you cannot manually fix up this old state or successfully migrate it to the new state format you face the possibility of loosing data.
It seems to me that at this place of vulnerability, platform infrastructure needs to be very extensible. This ought the place where you can modify, extend or replace platform behavior.
What do you think?