A state machines is one of the Gang of Four design patterns. State machines are used to track activities or workflows. These workflows may be sequential, or they may fork, or they may even loop back on themselves. Tracking the workflow may be as easy as having an enum property on your object, or it could take an entire domain aggregate to determine an object’s state. Depending on the complexity, you may even have workflows that spawn later workflows.
Starting Simple: Task
A task is an object has a state: it is either complete or not. It’s a really simple class.
public class Task
{
public int Id { get; set; }
public string Description { get; set; }
public bool IsComplete { get; set; }
}
Applying Domain-Driven Design
That’s terribly simple. Maybe we should take a hint from Domain-Driven Design. DDD says that our objects (i.e. tasks) are nouns and methods are the verbs those knowns can perform. In this case, we should be able to complete a task. That means that our task needs a Complete() method.
public class Task
{
public int Id { get; set; }
public string Description { get; set; }
public bool IsComplete { get; private set; }
public static Task Create(string description)
{
return new Task
{
Description = description,
IsComplete = false
};
}
public void Complete()
{
IsComplete = true;
}
}
Now we’re thinking about a problem domain. Progress! Instead of exposing the setter for IsComplete, we’re thinking about workflow! When we create a task, we’re saying that task has not yet been done. Then we complete a task, which changes the flag. I bet you can even see the UI start to develop for this.

We’d even build nice urls to complete a task: POST: /tasks/123/complete. You can even see the MVC pattern emerge, can’t you. We fetch a task from a database, call it’s Complete() method and save it back to the database. What could be simpler?
We still have problems though. What happens when we call complete on a task that is already complete? Is suppose that nothing bad happens. We just took a boolean value that was true and set it to true (again). No harm really, but it’s a process that doesn’t make sense. While your data is still intact, your application is not behaving to expectations. If we built our UI correctly, we shouldn’t be showing completed tasks to users. Or if we do, the button should be disabled. No matter how you slice it, something is wrong.
Let’s fix the broken thing.
public void Complete()
{
if (IsComplete)
throw new ApplicationException(string.Format("Unabled to complete task {0}. Task is already complete.", Id));
IsComplete = true;
}
Now, the problem is solved, and there is little else to do.
In this example, a state machine is probably overkill. So let’s go on to something bigger.
Sequential State: Task (Round 2)
Let’s suppose some tasks take a while to do, or there’s a lot of tasks - anything to create a queue of work to be done. There’s a difference between an ‘open’ state and a ‘started’ state. And let’s suppose that you’ve been married long enough to know that a task isn’t done until your significant other says it’s done. A boolean isn’t going suffice any longer. Since we’re utilizing a DDD approach, we also need more methods to cover changes in state.
public enum TaskStatus
{
Opened, Started, PendingApproval, Completed
}
public class Task
{
/* ...snip... */
public TaskStatus Status { get; private set; }
/* ...snip... */
public void Start() { /* etc. */ }
public void WaitForApproval() { /* etc. */ }
public void Complete() { /* etc. */ }
}
We’re also going to have a lot more if blocks. In this problem, we cannot go from Open to Completed, so we’re going to have to throw exceptions if we try to do so. Also, we may need to go backwards. Your spouse can send a task from PendingApproval back to Started, but you cannot. So we’ll do something creative, like inspect the current user, to figure out how to answer that question. Now, a state machine starts to make a lot more sense.
The State Object
Our Task object is going to get really busy with a lot of methods and operations to handle it’s state. We’re going to need to add a lot of boolean accessors to handle things like CanStart, CanWaitForApproval, CanComplete. Instead of putting a lot of extra methods and properties on our Task object, let’s create a new object to hold state. We’ll move those transition methods from the Task object to the TaskState object.
public class TaskState
{
private readonly Task task;
private readonly IPrincipal user;
public TaskState(Task task)
{
this.task = task;
user = GetCurrentApplicationUser(); /* get from machine user, application state, etc. */
}
public bool CanComplete
{
get { return task.Status == TaskStatus.PendingApproval && user.IsInRole("wife"); }
}
public bool CanStart
{
get { return task.Status == TaskStatus.Open || (user.IsInRole("wife") && task.Status == TaskStatus.PendingApproval); }
}
/* ...snip... */
public void Complete()
{
if (!CanComplete)
throw new ApplicationException("Unable to complete...");
task.Status = TaskStatus.Complete;
}
}
Also, our task will need to hold a reference to its state. This will replace all of the previous methods that it used to have.
public class Task
{
private TaskState state;
public TaskState State
{
get { return state ?? (state = new TaskState(this)); }
}
}
Public API Concerns
If this is your code, and your application is the only consumer of your code, you’re done at this point. If you have a public API, there’s no reason to break it. The guts of the method will look a little different, though.
public void Start()
{
State.Start();
}
Congratulations! We have just written a very simple state machine. In my next post, we’ll make this just a little more complicated, but a lot more useful.