Say you're writing a enterprise blogging app in Ruby on Rails. Should
draft, be states? Maybe your answer is yes, like it is for WordPress. Or you might think differently about this problem, given that it's an enterprise application.
Prerequisites for state machine
For now, let's assume that we're not dealing with hierarchical state machines. If you consider our blog post case, you could put
draft into a database column called
state and call it a day.
However, the core assumption is that each individual state is mutually exclusive. The blog post can either be published, or be trashed, or be a draft. In normal cases, you'd be okay with that.
Make sure that states really are mutually exclusive
In an enterprise application, I could argue that although
draft are mutually exclusive, they're not mutually exclusive with
When I trash a content, but decide to restore it, the system needs to know whether it should put it into
draft state or the
published state. In essence, a piece of content can be either draft and trashed, or published and trashed.
This is where you could argue that let's construct a state machine of two variables, publish status, and trash status. But it might have combinations that'd never occur, but you'd still have to account for that. The number of states would also grow exponentially with each additional workflow state that you add; say you decide to let people "flag" inappropriate content.
Consider independent workflows
A good way to design this would be to:
- Have a column called
- Have a column called
- Whether the content is published or not depends on both the above fields, and will depend on newer fields too as they're added. Thus add a
is_visible_to_userfield that indicates whether the content is publicly visible. A single combinational method in the
Postmodel would take all the fields above as input, and output a value for
- Workflows that show content only have to depend on the
is_visible_to_userfield, without caring for how it was computed.
Enterprise applications are not simple
Although we modeled draft content with a
is_draft column, in an enterprise application, there would be a lot of audit logs around the change of any of these columns.
Not everyone would be allowed to trash content too. So trash as a functionality could have additional audit tables describing who trashed it, when, and why. The
is_trashed field is basically a cache for this decision.
Individual workflows can be owned by different teams
An enterprise application often has a large team, which is often divided into smaller teams responsible for different parts of the application. Separating workflows into columns like these allow different teams to own the drafting and trashing functionality.
The only common denominator becomes the function inside of the
Post model that calculates
is_visible_to_user from the rest of the fields. Code reviews become easier, and it becomes easier for the team to move ahead with implementing its functionality.
When thinking about using a state machine, make sure that you've fully evaluated the nature of the states, while also considering your team size and the general direction for the development of your feature.