When you are working with a set of predictable events, you will more often than not be engaged in sequential workflow. For instance, in the previous chapter you created an uncomplicated workflow example, WFOrderStatus, with simple rules that propelled you to completion. Even though the path of execution branched and looped, the rules you had defined dictated how you got from one part of the workflow to the next.
But what do you do when you are dependent on external events to advance your workflow? The answer is usually to build a state machine, which is a behavioral model composed of various activities, states, and transitions between those states. This is a task that traditionally has been easy to get almost right but terribly difficult to get completely correct. WF, however, makes creating state machines natural.
Perhaps more important, WF allows you to map a state machine to your problem domain neatly and directly, thereby dramatically reducing your cognitive load and allowing you to solve more complex problems with easier-to-maintain code.
State machines are often implemented as threads (or processes) that communicate with one another, triggered by consuming events, all as part of a larger application. As an example, an individual car in a traffic simulation might be implemented as an event-driven finite state machine (as, for that matter, might the entire traffic simulation itself).
Another way of thinking about this Cartesian ...