S.O.P. – Eliminate all Conditionals? No.
In the previous article I mentioned that S.O.P. is about using State & State Transitions to pre-determine the actions that code should execute as opposed to using Conditional Statements (if, switches…) to check Current State to determine what to do. The advantage being that decisions are made at the point that State changes as opposed to later on, when it can be difficult to understand how the code reached a certain State. (You know the Scenario where “Computer, She say No”, without knowing why “Computer say No”)
However, SOP is not about eliminating Conditional Statements, rather it is about using State transitions to pre-determine actions to be performed as opposed to testing State at the time to determine what action to take. In particular, you may need to use conditional statements to determine that state has changed. For example when a state change is triggered by a numeric attribute reaching a certain value. i.e. a bank account reaching zero.
Other situations that can require the inclusions of conditionals is when the language constructs themselves do not allow for any other mechaism. I highlighted one such situation in the Calculator example, where the only mechanism provided by C# to check whether an event has been subscribed to is to check if it is null. Personally I think this is a shortcoming of the Event implementation, but it is not that big a deal.
Another example is checking whether a collection contains a certain item. Again I personally would like to see collections with events that can be fired when certain triggers occur (such as Object of given type added/removed). This way an Observering object can be informed when a collection receives an item of interest.
One last case is the ‘null’ check. For the most part these checks should not be necessary. If a properety being null is not an acceptable condition, then the property should never be null. If it is an acceptable condition, then whoever is consuming the property should operate accordingly. (Of course this does imply having events on the property to know when it changes but I will come to that later). The only time a null check is necessary is when a method/function receives input and that input must not be null. However, if languages allowed Guard conditions to be imposed on functions (such as Erlang or Swift ), then these situations would be handled without the need to resort to:
if (x == null)
{
throw new ArgumentNullException("X cannot be null");
}
And in case you think the above is hardly arduous. If you have ever used Dependency Injection (which I hope you have), then you will know that every constructor starts with checks like the above for every non primative parameter passed in.
State Transitions
In the calculator example we used a simple dictionary structure to hold the both a state transition action and the effective state to transition to. A more generic approach would be to have:
- Set of State Exit actions
- State to Transition to
- Set of State arrival actions
Further it is not unsual to have an object with multiple state maps
Local and External State
In the calculator example all the State transitions that relate to the Calculator are all local to the object itself. More complex systems in which multiple objects interact mean that the State of Object A will change depending on the state(s) of Object B, C ….. ie The State of Object A is determined externally.
Scenarios with External state are not only extremely usual they are the most troublesome. These are the cause of the “Computer says ‘No'” syndrome. A state has been reached that the code does not cater for and the only recourse is to stop processing. No indication of the problem, no help in trying to resolve the issue. With S.O.P. it would at least be possible to detail the State of the various objects, which combined with the State Maps would indicate why there is a problem.
Now where Objects are aware that changes of state may be of interest to others, they can provide Events to which others can subscribe. However, where an Object is not aware that its property is of interest to others, or if an Object was not written with SOP in mind, then it will not have the necessary handles to allow its state to be monitored.
With C# Extension functions we can get round this.
As an example lets examine a classic interview question – Modelling Lifts in a Building
Modelling Lifts in a Building
Objects & States
- Building
- Floors
- Users
- Lifts
- LiftController
- LiftRequestSignal