OK so I'm working on quite a fun project; it's a proof of concept for a near-real-time, pub-sub, server to client push type communicaton subsystem.  Phew.

Essentially it's a big fat wrapper around a few candidate technologies including SIP, a.k.a. our RTCClient API, v1.3.  THAT  (RTCClient) will be the subject of another blog I'm sure.  Getting a multithreaded .NET server app to manage and use multiple STA-threaded COM objects was quite fun...

The heart of the wrapper is a quasi-reliable-messaging protocol.  Because the underlying communication API's don't all offer reliability, we had to engineer our own.  It doesn't have to be as bulletproof as MSMQ or other reliable systems; it just has to be Pretty Darn Good.

I went with the obvious solution; messages with sequence numbers, and a heartbeat system telling all clients on a regular schedule what the latest sequence number for a topic is.  Clients can detect missed messages and request historical updates.  There's some complexity as we have to account for out-of-order receiving, rolling over Int32.MaxValue sequence number cleanly, etc.

So where's the State Pattern?

Right, enough preamble.  I had this really nasty method with a TON of if-then's, some with composite tests--lots of &&'s and ||'s scattered around.  I **FEAR** such methods from painful experience going back to age 10 and writing a PacMan in assembly.

I busted out C#Refactory (http://www.xtreme-simplicity.net/, best 100 bucks you'll ever spend on a coding tool).  Sure enough, the Cyclomatic Complexity of said method was 10--and 10 is a magic number.  That is the cyclomatic complexity at which it is almost _certain_ you will create a bug when modifying the method.  And, the fates help that poor developer who comes after me and has to mentally compile that pile of doo I wrote!!

Here's where the State pattern comes in.  Separate state representation from behavior, and allow flexibility and extensibility of the system.  In fact it just recognizes the key fact:  those long-winded if-then methods we hate to debug are in fact finite state machines, and should be written that way...Take a peek at http://msdn.microsoft.com/msdnmag/issues/01/07/patterns/ for a great example of when/how to use State.

My case wasn't really amenable to the iterative type of State machine there though.  Most State implementations assume the vending machine analogy, or the bank account status, etc.  You send messages to the FSM and it migrates between nodes in response. 

Mine had to work with a known set of inputs, present from the outset.  I had to get the information--the "language" I'd feed the FSM--and ask the FSM to find the right output state for that input right away.

So I created a State abstract base class, with properties to describe the State--in this case, HaveMissedMessages, IsBadState, and TrueSequenceNumber.  Those three describe fully what conditions we can be in.  See the abbreviated source below.

But here's the departure from usual State implementations:  I'm going to call it Statically Found State because I'm naming-impaired:

I don't pass my Context into the State.  In fact State knows _nothing_ about its users; most State patterns have to know about their context--their user, the behavior thing above them.  They also often mimic all the methods of the context; so their signature can be quite cluttered.  They don't JUST have the properties that define the current State.

Instead I have a static method defined on the State base and all derivatives, "FindOutputState".  Each class implements its own version of FindOutputState.  Each class knows what inputs correspond to which of its immediate neighbor nodes.  It then calls FindOutputState on the appropriate next neighbor in the graph.

That next neighbor, again, knows only about its immediate neighbors and what inputs would transition to one of them.

Eventually you have a final state with no exits--you've gone to ground and the FSM ends.

In this system the output states are InSynchState--we have not missed any messages--OutOfSynchState--we've missed some but we're recoverable--and BadState, which happens when you're so far off it's ridiculous.

The inputs are InternalSequence, which is what we believe is our sequence, ExternalSequence--what we received--and whether the message was a Message or a Heartbeat.  The latter is important because the semantics are subtly different.

I abbreviated the code below a little 'cause this editor blows every CRLF into a fat double-spaced linefeed.  The important parts--implementations of FindOutputState--are bold and indented.

Why I Love the State Pattern:

It separates state from behavior.  It formally expresses each node of the FSM, rather than burying them in the scope of some if-then clause.  I can add new States and inject it between existing nodes with little effort.  The very existence of each State derivate class verbalizes that node formally, calling out an anticipated intermediate. 

Note that the most complex FindOutputState has a CC of only 4--much easier to NUnit test.  In fact using the State pattern is wonderful for TDD, because you can test your FSM without any of the crufty context you usually need to inject to get at those long if-then-elseif poopy methods.

Question:  is this a new pattern?  Or am I totally deluded?  Do the departures from the usual State implementation seem valuable?

Here's the code:

public State(){}

protected const int ROLLOVER_THRESHOLD = 10000;

private int _trueSequenceNumber = 0;

protected bool _haveMissedMessages = false;

protected bool _isBadState = false;

public static State FindOutputState( bool isMessage, int intSeq, int extSeq )

{

State state = null;

if( isMessage )

state = MessageState.FindOutputState( isMessage, intSeq, extSeq );

else

state = HeartBeatState.FindOutputState( isMessage, intSeq, extSeq );

return state;

}

public bool HaveMissedMessages

public bool IsBadState

int TrueSequenceNumber

}

internal sealed class MessageState : State

{

public MessageState(){}

public new static State FindOutputState( bool isMessage, int intSeq, int extSeq )

{

// easy one first: all inputs that lead to InSynchState:

if( intSeq == extSeq )

return InSynchState.FindOutputState( isMessage, intSeq, extSeq );

// external sequence is internal plus one, basically OK

if( intSeq == ( extSeq - 1 ) )

return InSynchState.FindOutputState( isMessage, intSeq, extSeq );

// second easiest next; out of synch by more than one difference

if( intSeq < ( extSeq - 1 ) )

return OutOfSynchState.FindOutputState( isMessage, intSeq, extSeq );

// OK now for the rollovers;

// if internal is more than external pass off to rollover handler

if( intSeq > extSeq )

return MessageRolloverState.FindOutputState( isMessage, intSeq, extSeq );

return BadState.FindOutputState( isMessage, intSeq, extSeq );

}

}

/// <summary>

/// Leaf node. Internal was behind external by a recoverable amount.

/// </summary>

internal sealed class OutOfSynchState : State

{

public OutOfSynchState(){}

public new static State FindOutputState( bool isMessage, int intSeq, int extSeq )

{

// leaf node; we are out of synch but recoverable

State state = new OutOfSynchState();

state.HaveMissedMessages = true;

state.IsBadState = false;

state.TrueSequenceNumber = extSeq;

return state;

}

}