Generate State Machine diagrams from your POCO Entities
Have you ever come across those tools that let you generate code from state machine diagrams or state tables? Just for fun, I thought I'd try turning that idea on it's head:
"Don't use a modeling tool or DSL to generate code. Instead, use a fluent interface to express state machines in your POCO entities. Then, automatically generate diagrams from the code, and use these to facilitate communication with project stakeholders. "
Note: I haven't posted the full code up here, just snippets*
1. Create State Machine framework with fluent interface
I started by writing a lightweight State Machine framework (<100 LOC). This is quite easy really. I gave it a fluent interface that allows state transitions to be expressed in readable code (see below).
2. Create POCO entity
Then created an example domain entity that used the framework. I gave it some states, set up tranistions between those states, and added a method to trigger a transition.

The event is the Raise() method, which attempts to make a transition. The transition succeeds if it is a legal path and no validation errors occur.
ValidationDraftToRaised() is called automatically by the framework at runtime, during the transition. If there are validation errors, the transition fails.
3. Auto-Generate Statechart
I can generate a state chart for any entity in my system.
This chart was produced automatically from the code above. It is produced at runtime by using reflecting on the POCO to see what states and transitions we set up using the fluent interface.

The generator actually outputs in dot notation, and is great for representing state machines. Below is an example of use, I'm just showing the interface, rather than the implementation.

Does this idea have legs?
There's something very cool about coding the state machine with a fluent interface right inside the POCO, and then automatically generating a visual graph to facilitate discussion and communication. I like the fact that the knowledge is encapsulated in the POCO entities; no additional tools, state matrices or languages are required during the build cycle.
All that said, I'm not buying this this idea yet. It is kind of fun, but having FSM semantics mingling with business domain semantics makes me a little uncomfortable. Also, if my light FSM framework needs to handle more complex cases (superstates, for example), then this approach might be even more invasive.
Thoughts anyone?
Next Steps
If I persue this experiment, I have a few other ideas:
State Machine Self Diagnosis. It will be able to check for common problems with the state machine setup: a
Statethat never gets transitioned to, guard clauses that will never be called etc.Unit Testing Integration I'd like to expose those problems to NUnit, so that the unit testing catches any misuse of the DSL.
Something like this
public void TestPurchaseOrderStateMachine()
{
foreach( CheckResult result in StateMachine.Check( typeof( PurchaseOrder ) )
{
Assert.IsTrue( result.Ok, result.Error );
}
}
Which might output something like
10 Assertions. 3 Ok. 2 Failed.
State Machine Error. PurchaseOrder state "Cancelled" will never be transitioned to.
State Machine Error. Guard method "ValidateRaisedToCancelled" will never be invoked.
That's it for now, any thoughts welcome!
Comments
-
For a lightweight state machine it looks nice. How hard would it be creating a graphical designer for something like this?
-
I’m was toying with the idea of using the Visual Studio SDK to write a state machine designer/visualiser.
However, I’d want really pretty code generation, that makes elegant use of the fluent interface leaving code easy to understand and extend.
I haven’t personally had that much success with working with graphical designers, mainly because I tend to reach their limits at some point, and have to drop back into code.
That said, I love the concept of working at higher levels of abstraction in a designer.
In summary, I’d love to have a designer, but I’m afraid that it would be too much work to get it to generate pretty, readable, extendable code.