The oversimplification of the Event-Action Paradigm
The currently dominating approach to structuring event-driven software is the ubiquitous "event-action" paradigm, in which events are directly mapped to the code that is supposed to be executed in response. The event-action paradigm is an important stepping stone for understanding state machines, so in this section I briefly describe how it works in practice.
I will use an example from the graphical user interface (GUI) domain, given that GUIs make exemplary event-driven systems. In the book Constructing the User Interface with Statecharts, Ian Horrocks discusses a simple GUI calculator application distributed in millions of copies as a sample program with Microsoft Visual Basic, in which he found a number of serious problems.2 As Horrocks notes, the point of this analysis is not to criticize this particular program but to identify the shortcomings of the general principles used in its construction.
When you launch the Visual Basic calculator (available from the companion web site at www.state-machine.com/psicc2/, in the directory <qp>\resources\vb\calc.exe), you will certainly find out that most of the time it correctly adds, subtracts, multiplies, and divides (see Figure 2.1a). What's not to like? However, play with the program for a while longer and you can discover many corner cases in which the calculator provides misleading results, freezes, or crashes altogether.
Figure 2.1: Visual Basic calculator before the crash (a) and after a crash with a runtime error (b).
For example, the Visual Basic calculator often has problems with the "–" event; just try the following sequence of operations: 2, –, –, –, 2, =. The application crashes with a runtime error (see Figure 2.1b). This is because the same button (–) is used to negate a number and to enter the subtraction operator. The correct interpretation of the "–" button-click event, therefore, depends on the context, or mode, in which it occurs. Likewise, the CE (Cancel Entry) button occasionally works erroneously--try 2, x, CE, 3, =, and observe that CE had no effect, even though it appears to cancel the 2 entry from the display. Again, CE should behave differently when canceling an operand than canceling an operator. As it turns out, the application handles the CE event always the same way, regardless of the context. At this point, you probably have noticed an emerging pattern. The application is especially vulnerable to events that require different handling depending on the context.