The Art of States and Transitions — II
Previously, we had looked into some concepts related to state-machines (link <a href="https://www.getdefault.in/post/the-art-of-states-and-transitions-i" style="color:#0057FF; text-decoration:none;">here</a>). In this part, we’ll shape a state-machine for an e-commerce flow.
Before proceeding any further, one must realise that for a non-zero distance interaction layer, it is very important to consider the infrastructure that hosts the entire application, because there is a void between the business layer and the interaction layer.
What does that mean?
Communication between the two layers happens through a well-established set of rules, also known as protocols. If a protocol is stateful (e.g. FTP, SMTP), there isn’t any issue. But if the protocol is stateless (e.g. HTTP), then the void allows any client to trigger any event irrespective of the current state of that client maintained in the application layer’s memory. This isn’t much of an issue if the environment is constrained (e.g. organisation intranet), but that’s hardly the case with modern distributed applications intended to be used/consumed worldwide, and as more and more applications become API driven, considerable thought has to be given to solve such problems.
To alleviate such issues, one has to rethink the application model first: both mentally and in design. An example would clarify the situation.
For an e-commerce website, the general thought process in terms of state is:
It is understandable that one cannot place an order if one is not logged in; however, from a non-zero distance interaction layer, there’s nothing stopping one from placing an order (right after logging in) when no items were even added in the first place. Remember, that state-machines with proper modeling allow one to make impossible states impossible to occur. Well, that’s what we’ll do next.
The solution is to reason by first principles, which in this case is modeling the entire sequential journey for just a unit product.
And now, one can only place an order when there is at least one item in the cart.
But another issue surfaces. What if one wants to place an order for multiple items? The above transitions don’t incorporate that.
Yes, it doesn’t. Because the journey was designed for a unit product. Any solution?
Enter HATEOAS (Hypermedia As The Engine Of Application State), or more specifically, the concept. It is a constraint of the REST architectural style of application development wherein an application server provides information to the client dynamically through hypermedia. We can apply this concept to our example.
It must be kept in mind that if an application is developed using RESTful architectural style, then HATEOAS is a constraint and is not optional, because this allows the application layer and the interaction layer of a non-zero orthogonal system to evolve independently, essentially decoupling the layers.
Depending on the current state, we can expose allowable events to the interaction layer for it to trigger. One possible state-transition diagram (after some refactoring) is shown below.
1. Applicable events can be further constrained by introducing guards, which when satisfies certain conditions depending on the current context and state, can either introduce/remove events, e.g. if there are no more items to view, the view-more event will not be forwarded to the interaction layer
2. Interaction layer can introduce caching so that existing items already viewed, stay in memory rather than re-fetching them; consequently, events can be modeled as parameterized functions, e.g. to implement pagination by providing pageNumber and limit by passing them directly as arguments to the event or through a payload (incase of utilizing state-machine through HTTP)
3. Events in the above transition diagram are analogous to URIs with attached payload (if any)
4. The checkout event can only happen when there’s at least one item in the cart, but it also inherits the logged-in status, thus indicating that events exposed through HATEOAS are state-dependent
5. A state-machine with HATEOAS constraints behaves like a Mealy machine, whilst without HATEOAS constraints, as a Moore machine
Most authors of state-machine libraries implement them in a standard way as laid out in automata theory, but there exists subtle differences owing to either programming language constraints, or protocol constraints, or orthogonality, or tuning state-machines for a particular domain(s), or renaming terminologies to what they feel deem fit, or stripping functionalities to make it minimal, or adding functionalities to let it handle all possible scenarios, and so on. These differences often confuse developers when they begin developing software through the state-machine model, or when they trade one implementation for another due to factors such as time limits, business constraints, or documentation issues.
Whatever the underlying implementation, first and foremost, it should be kept in mind that the business logic must suit the state-machine model of development; and if so: then if it is assumed that over time the state-machine will become complex, consider using a state-chart that allows states to be organized in a hierarchy.
It is hoped that the entire article clarifies doubts regarding state-machine usage and/or implementation.