Implicit vs. Explicit State MachinesWhether or not you plan for it, your code will inherently be state driven. For example, developers often change the enabled or visible property of a control to false (for example, TextBox1.Visible = false;) when the application is in a state where the control is not valid for user interaction. There are two approaches to writing this kind of code: Approach 1: An Ad Hoc, Decentralized, and Implicit Approach to State Management (Bad Design)Many applications that grow gradually more complex exhibit this kind of ad hoc design. Aspects of the application's state are changed in many different locations. State data is held in properties such as the Visible, Enabled, Size, or Position properties of controls. Variables that hold key state data are changed in-line by whatever code needs to have it happen, and the loading or discarding of application data happens in a distributed and ad hoc way. This results in a tug-of-war between different parts of the application as each new function does whatever it needs to do to get its work done without regard to the rest of the application. The most common example of this is having event code that responds to a user interface event such as clicking a button containing in-line code that changes the state of the application. Listing 5.2 contains code that could typically be found inside an application's form class that follows this ad hoc approach. Both code for the form1 "load event" and the button1 "click event" make changes that affect the overall state of the form. Listing 5.2. Application State Being Changed Implicitly (Bad Design)
Approach 2: A Planned, Centralized, and Explicit Approach to State Management (Good Design)In contrast to ad hoc state management is explicit state management. With this approach, all state changes happen through a central function. Event code that needs to change some aspect of the application's state does so through a single function that all other code that also needs to change the application's state also calls and defers to for state transition logic. Listing 5.3 shows an example of this approach. Listing 5.3. Application State Being Changed Explicitly (Good Design)
The code above performs the same tasks as the previous example but does so in a well-encapsulated way. Each user interface element's event handling code does not directly modify the user interface's state but instead calls a central state-management function to perform the necessary work. This process scales well as our application grows and changes. If we need to change some aspect of the way our user interface works, our application has a central function that does this. As we add additional controls or additional application states, we have a central and well-understood way to incorporate these additions into our programming model. Whether or not you realize it, a significant portion your application's code relates to managing its state. You are in the state machine business anyway and can either choose to approach it explicitly or not choose it and end up with an implicit model. Approaching state explicitly has significant benefits, not the least of which is that it will force you into a mindset where you think more crisply about the way your application operates. Much early application development and prototyping work tends to happen informally. This should not discourage you from using state machines. On the contrary, state machines can be of great value here as well. As you can see from above, the extra code in using a state machine approach is minimal. It is very easy to add new states, delete states, and rename states to meet changing definitions as you work out an idea. I find state machines particularly useful in designing mobile application user interfaces because it gives me a central place to play around with control positioning and resizing logic. Even in ad hoc development, a state machine approach can save time and give you flexibility in exploring your ideas. |