© Leon Starr, Andrew Mangogna and Stephen Mellor 2017

Leon Starr, Andrew Mangogna and Stephen Mellor, Models to Code, 10.1007/978-1-4842-2217-1_2

2. A Simple Executable Model

Leon Starr, Andrew Mangogna2 and Stephen Mellor1

(1)San Francisco, California, USA

(2)Nipomo, California, USA

This chapter describes the main elements that make up an executable model for a sample application. The application is deliberately small so that we can show how to translate the whole model into running code, with no mysterious gaps. We’ll use the same principles later to build larger, more complex applications.

This chapter also serves to explain our interpretation of UML graphical notation. We use UML graphical notation to represent the model, but xUML varies considerably in the semantics that apply to that notation. We want to make sure you understand the meanings we attribute to the graphical symbols.

While reading through this chapter, you may find it helpful to refer to Appendix A, which summarizes key xUML notation and semantics.

An Air Traffic Controller Application

The air traffic control application manages air traffic controllers (ATCs) in a control center. The system ensures that all local air traffic is directed and that the ATCs take appropriate breaks. Figure 2-1 shows their world.

A421575_1_En_2_Fig1_HTML.jpg
Figure 2-1. An air traffic control center

The application must do the following:

  • Log an air traffic controller (ATC) onto a duty station

  • Record the zones under the control of a duty station

  • Verify that a control zone is always under the control of a duty station

  • Record the handoff of a control zone to another duty station

  • Log an ATC off a duty station

  • Prevent an ATC working a shift longer than 2 hours 15 minutes

This description is surely incomplete and insufficient for us to build the application, but it’s a start. Some would suggest investigating further and tying down details in a requirements document; others, of a more agile persuasion, would recommend writing executable code to explore the application in the absence of a complete understanding. We take the best of both worlds and build a detailed executable model that we can use to investigate the application in more detail. We can use the model for evaluation, we can run it, and we can test it. And when we’re satisfied, we can translate it directly into code.

We build the model as three interconnecting facets, as shown in Figure 2-2.

A421575_1_En_2_Fig2_HTML.jpg
Figure 2-2. The three facets of the modeling language

The first facet is a class model, which declares the conceptual entities in the system. We use a limited subset of UML class diagram notation to represent the model. The class model defines classes, their attributes, and the associations between classes.

The second facet consists of state models, which describe the behavior of a class over time. Again, we use a subset of the UML state machine diagram notation to represent the model. There is a state model for each class. There is a copy of the state model, a state machine, for each class instance. Each state machine and, therefore, each instance, has its own independent notion of its current state. Most of the dynamic behavior in a model takes place in the context of a state machine.

The third facet is actions. Actions give the details of computation and other algorithmic processing. Depending on how the actions are represented, they might look like code. However, actions are really the specification of model-level computations on model-level elements, and that is a better way to think of them.

Each of these three facets represents a single perspective of the system. They fit together into a coherent whole that represents a solution to the logical problem your application poses. The integrated facets define a complete, executable domain that can be translated into code. A domain is a coherent subject matter with its own set of policies and rules. Generally, applications are composed of multiple domains that interact to satisfy the whole set of application requirements. There is more to be said about domains, and we will take that up in Chapter 6. For now, it is enough to know that a modeled domain is an independently executable and testable composition of all three facets.

The order of model construction is significant:

  • Class model, to capture definitions, data, rules, and constraints

  • State models, to capture modes, control intervals, and synchronization

  • Actions, to capture signaling, data manipulation, and computation

Each step lays a foundation and a constraining framework for the next. For example, the fact that a shift ends at a certain time (contained in the class model) is more fundamental than the exact manner in which the time is determined (contained in the state models and actions). So we nail down the elements least likely to change first, with the more volatile elements defined and added later. This approach sets up a stable underlying structure upon which to build, and decreases the overall refactoring required whenever a change occurs.

It is important to realize that executability depends on all three facets. You must know how you are computing (actions), when you are computing (state models), and exactly the data on which you are computing (class model).

Step 1: The Class Model

Figure 2-3 shows a class model for the ATC system. It has been annotated so we can point out our interpretation of the graphical symbols.

A421575_1_En_2_Fig3_HTML.gif
Figure 2-3. Annotated class diagram
  • ❶ Each box represents a class. A class is an abstraction of a set of physical or hypothetical things having common behavior, common characteristics, and subject to the same rules and policies—in this example, a Control Zone. Each instance of a class is called an object or an instance. We will use the terms interchangeably. The second compartment contains a list of attributes that define the data required for each instance. Each Control Zone is described by a name, the amount of traffic, and the current controller.

  • ❷ An identifying attribute is indicated by the tag {I}. The set of identifying attributes for a class comprises its identifier, which constrains the instances so that no two of them may have the same values for the identifying attributes. This also constrains the instances of a class to be a set. In this case, no two Control Zones may have the same Name. The identifier is often useful application data (the name of the Control Zone, for example), but sometimes it is entirely manufactured. When the model is translated, the identifiers may be transformed or substituted by something more appropriate to the implementation. As long as the identity constraint is met, the translation is free to transform the identifiers in any way.

  • ❸ A descriptive attribute has a data type, shown after the name and a colon. We capture the type in application terms (for example, a whole number of airplanes between 0 and 200). After we have defined all the actions that operate on the attribute, we can decide how to represent the type in a program.

  • ❹ A referential attribute is indicated by the tag {R}. This tells us that the attribute refers to another instance—in this case, the controller directing the Control Zone. By refers, we mean the value of the attribute in the instance has the same value as an attribute in another instance. The Control Zone.Controller attribute tells us which controller is monitoring a particular instance of Control Zone. However, the rules of the domain insist that the controller must be on duty. So, the value of the Control Zone.Controller referential attribute is constrained to match the value of an instance’s On Duty Controller.ID. At implementation time, this may be implemented in many ways, such as a foreign-key constraint in a database or simply as a check on a pointer value.

  • ❺ This line between the two boxes, labeled R2, is an association relationship. It represents the relationship that exists between On Duty Controller and Control Zone entities in the real world. Each association has a unique number—in this case, 2. By convention, we label the graphic with an R, followed by its number; for example, R2. The unique number is required because more than one association may exist between the same two classes (for example, a person may both drive one car and own other cars).

  • ❻ These are association phrases. These verb phrases are textual annotations that tell us important semantic information about the relationship and provide a mnemonic for how to describe the real-world association. We can say that an On Duty Controller is directing traffic within a Control Zone. Similarly, there is a passive-voiced version of the relationship stating that a Control Zone has traffic directed by an On Duty Controller. The phrasing is constructed to read in both directions as a “subject—verb phrase—object” sentence with the verb phrase for a given direction being placed on the diagram nearer to the class that serves in the object role.

  • You may be more familiar with the UML style of using role names. We find, from extensive practice, that the verb phrase style is almost always more precise and expressive. Also, it is much easier to just say, “is directing traffic within,” than to contrive a role for a Control Zone. We also find that it is much easier to establish the correct multiplicity and conditionality by considering a verb phrase. In fact, the practice of carefully naming both sides of each association with precise verb phrases frequently exposes contradictions, ambiguities, and incompleteness in the source requirements.

  • ❼ We always further constrain an association by defining its multiplicity and conditionality for each side. The multiplicity specifies whether more than one instance may be involved in the association. The conditionality specifies whether an instance is required to participate in the association. The two concepts are combined into one graphical symbol, so, for example, “0..*” for R2 on the Control Zone side says that an On Duty Controller is directing traffic in zero or more Control Zones. The purpose of the multiplicity and conditionality of an association is to constrain the membership of the set of instances of a class.

  • ❽ This indicates a generalization relationship. The arrow points to the superclass, which is a generalization of all of its subclasses. In this example, an Air Traffic Controller can be either an Off Duty Controller or an On Duty Controller, and not both. A specific controller (Ianto, for example) will be both an Air Traffic Controller and an On Duty Controller. He is described then by attributes ID, Name, Rating, a Time logged in, and the Duty Station he currently controls. Our xUML interpretation of generalization is much more restrictive than that of conventional UML. We consider a generalization as a set partition and that the superclass instances are a disjoint union of all the subclass instances. UML would label this as {disjoint, complete}. Because we have only a single specific interpretation, we omit the annotation from here on. Further, we do not imply any notion of inheritance on the generalization. We treat the superclass and subclass instances separately. We interpret generalization relationships as meaning there is an unconditional, singular association between a subclass instance and a superclass instance, and an unconditional, singular association between a superclass instance and a subclass instance from among all the subclasses of the generalization.

  • ❾ This isn’t done often, but it is perfectly legal for a class not to be connected via any association. In this case, there is only one instance of Shift Specification that defines a couple of durations applicable to all Air Traffic Controllers. Because there is only one, it is easily selected without requiring any relationship traversal. (This would change if different groups of Air Traffic Controllers were subject to different break periods.)

There is a good deal more to be said about class models, and whole books have been written about them, such as Executable UML: A Foundation for Model-Driven Architecture by Stephen Mellor and Marc Balcer (Addison-Wesley Professional, 2002) and Model Driven Architecture with Executable UML by Chris Raistrick et al. (Cambridge University Press, 2004). Moreover, there is a good deal more to be said about how to go about constructing class models, and whole books have been written about that too. For example, Executable UML: How to Build Class Models by Leon Starr (Prentice Hall, 2001). We recommend that you read them, because a complete model must be constructed before translation, and translating a poor model yields an equally poor implementation.

Interpretation

The class model says a great deal about the application with just a few, well-defined elements. Class models provide a precise and unambiguous vocabulary with which to explain and discuss a problem. When we talk of a Control Zone, we mean the exact Control Zone declared on the model, as characterized by its attributes, and nothing else. It is Humpty Dumpty speak1 that enforces the precision necessary for a meaningful discussion of problem logic.

For example, an On Duty Controller requires an ID, a time logged in, and a Duty Station to be working at, whereas an Off Duty Controller must have an ID and a date the last shift ended. The declaration of On and Off Duty Controllers allows us to differentiate between them, preventing an Off Duty Controller from being logged in, and requiring an Off Duty Controller to have a break. Obviously. But it would not have been obvious had we just plopped down an ATC with no subclasses. Such a model would have allowed an Off Duty Controller to direct traffic within Control Zones, even though, in the real world, this is prohibited.

The placement of attributes constrains our understanding of the meaning of a class, because each of its attributes must apply uniformly to all instances of that class. For example, the attribute Duty Station.Capacity places a maximum number of aircraft on each Duty Station, whereas an attribute Control Zone.Capacity would place the maximum on the number of aircraft controlled by the Control Zone, thus limiting the sum of the aircraft in each Control Zone, rather than all of them. A detail, certainly. But code is detailed, and the code for those two interpretations is quite different.

We also need to be certain we understand the precise meaning of each attribute. For example, what exactly is the meaning of Control Zone.Traffic? Is it the current number of aircraft in the zone? A maximum? Something altogether different? We must tack these down before we generate code, or the code we generate will be wrong. To capture this information, we must also write descriptions of each class, each attribute, and each association.

Associations impose constraints that hold throughout the operation of the system. For example, the multiplicity “0..*” on the Control Zone side of R2 tells us that an On Duty Controller logs in, and then takes over Control Zones, rather than being implicitly logged in after they take over the first Control Zone. It also means controllers must hand over their Control Zones before they log out. The multiplicity constrains the possible behavior of the associated things, which ties down their meanings more precisely.

These statements, the definitions of the classes, attribute placement, and the constraints imposed by multiplicity must be verified against the real world. If a controller can be considered on duty only when controlling at least one Control Zone, the model is wrong and it should be changed. Is it? We have to find out. We have to question and evaluate the implications of each element on the model systematically. The attribute Off Duty Controller.Last shift ended, for example, enforces adequate break time. What break time? That wasn’t in the preceding list of requirements! (It should have been: a minimum break time of 15 minutes is required.) And so on.

These rules apply when the system is in operation, not during initialization. When the system comes into existence, there will be no Duty Stations, controllers, nor zones, but it is useful to think of some classes as having preexisting instances. Controllers come and go, but Duty Stations can be considered to exist before the system comes into operation. Table 2-1 shows the instances of Duty Station that exist when the system starts running.

Table 2-1. Duty Station Instances

Number

Location

Capacity

DS1

Front

20

DS3

Center

30

DS2

Front

45

Similarly, Table 2-2 shows the preexisting instances of Control Zone.

Table 2-2. Control Zone Instances

Name

Traffic

Controller

SJC18C

30

ATC53

SFO37B

25

ATC53

OAK21C

15

ATC67

Here, we have represented the initial instance population of the Duty Station as a table, though, as usual, the implementation may be entirely different. For example, references to the Controller in the Control Zone table might be implemented by programming language constructs rather than the value comparison implied by a table.

Step 2: State Models

The class model expresses behavioral constraints, but it does not define the specific behavior over time. Each instance of a class is subject to the same rules and constraints, behaving the same way over time. An Air Traffic Controller object will be off duty initially, log in at some point, become on duty for a period of time, and eventually log out again and return to being off duty. This life cycle common to all ATCs is captured with a state model.

A state model is defined on a class, and all instances of that class exhibit the same behavior. At any given time, each instance will be in its own state, with other instances in possibly different states. This is why we have distinguished between a state model and a state machine. A state model is the pattern of states and events associated with a class and describes the behavior of all the instances of that class. A state machine describes the behavior of a single instance that is governed by that instance’s value of its current state.

Although we generally construct a state model for each class, we can omit the state model for a class that has no interesting behavior. Classes that simply come into existence and do not behave differently over time do not need a state model. In a generalization relationship, we have choices as to whether the state model is associated with the superclass or the subclasses. A complete set of rules and heuristics for their use can be found in Executable UML: A Foundation for Model-Driven Architecture.

Figure 2-4 shows the state model for the ATC. It also has been annotated so we can define our interpretation of the graphical symbols.

A421575_1_En_2_Fig4_HTML.gif
Figure 2-4. Air Traffic Controller life cycle
  • ❶ The rounded rectangular boxes are states. For readers familiar with state models from electrical engineering and math texts, in those contexts individual states are usually represented as circles. The rounded rectangles notation is more convenient because we like to write inside the boxes. The convention of using all capital letters for some state names indicates that an instance remains in that state until an event is delivered from a class instance other than itself or one that has been requested for a future time. By contrast, an instance in a mixed case named state will exit on a transition as soon as the activity is completed. This is only a notation convention that we have found useful and is not part of the execution rules for a state model.

  • ❷ The directed arrows represent transitions. An ATC who is Verifying Adequate Break may transition to either the Off Duty or Logging In state.

  • ❸ Each transition is caused by an event. If the break is adequate, the ATC will log in to a station, but if not, that event triggers the transition back to the Off Duty state. Strictly speaking, a distinction can be made between an event specification, which defines an event name and parameter signature, and the occurrence of a corresponding event at runtime directed at a particular instance, with values filled in for any parameters. In practice, however, it is convenient to just say event for either case unless the meaning is not clear from the context. In UML, a signal is something you send, and an event is something you detect, with several UML types of events defined. But, in xUML, we need only the type of event that is triggered by a signal. Consequently, in xUML, there is no distinction between signal and event, so we use the terms interchangeably.

  • ❹ Each event may carry event parameters. This is data carried along with the event that can used by the actions associated with the state. When ATCs log in, they log in to a specific duty station. This is rendered as the event parameter Station.

Interpretation

A state machine behaves as follows:

  • Each state machine is in exactly one state at a time.

  • When an event occurs, a transition is triggered and the state machine moves to a new state. The new state may be the same as its previous state, but it is considered to have transitioned even if it arrives back at the same place.

  • When entering a state, the state machine executes an activity comprising a particular number of actions (described in the next section).

  • How long that takes is indeterminate, but the state machine does not respond to any further events until it finishes the activity and reaches the next state.

  • When the state machine completes the activity of a state, it may respond to further events.

The last two bullets encapsulate a concept called run to completion: you finish what you’re doing before you start doing anything else. From an analysis point of view, you need not worry that an activity might be interrupted. For example, a state activity can manipulate the data in the class model without being concerned about transient inconsistencies in the activity’s processing. An activity can update longitude and latitude, for example, without having to worry about the data being misread halfway through the update. Run to completion ensures consistency of processing and simplifies the task of building models.

Beyond data consistency, this principle is critical to overall synchronization. To appreciate the importance of run to completion, consider what might happen if it were not true. Assume a hypothetical scenario in which a state activity generates a signal, and the dispatch of the corresponding event occurs as part of the signaling operation. The event dispatch might cause another state activity to execute, which in turn could signal back to the original sender. Again, if that event dispatch is executed synchronously to the signal generation, we would execute a new state activity in the instance before the original activity that generated the first signal completes. Such a situation might cause the underlying attribute values to differ, depending on whether they were accessed before or after signaling.

Events are neither saved nor lost; they are simply unavailable until the state machine settles in the next state and finishes its activity. Nor do we specify the mechanism whereby events are signaled or delivered. It is necessary only to presume that there is a pervasive, underlying means to execute the state machine event dispatch rules. The implementation of these rules can be accomplished in many ways, such as queuing an event until the state machine is able to respond. Later, we show exactly how this happens for our target execution environment. A summary of state, event, and activity synchronization rules is available in Appendix A.

There are two fundamental formulations of state models: in one, actions are associated with entering a state (Moore type model); and in the other, actions are associated with a transition (Mealy type model). Much ink, hot air, and electrons have been burned up in discussions of which formulation is better. In fact, a Mealy state model is easily converted into a Moore formulation, and vice versa, so there isn’t anything that you can model with one style that cannot be accommodated by the other.

In xUML, we use the Moore formulation, which means that an activity is executed when a state machine enters a state. In UML, these are called entry activities, and these are the only type of UML activities we need. Again, because we have only one interpretation of activities, we omit the UML entry / reserved word. xUML uses the Moore formulation because it yields a more regular state table that is essential for both translation and verifying event-state coverage. Moore state models associate activities with states, and this is convenient both for model specification and translation.

The dynamic behavior of a collection of state machines is as follows:

  • Each state machine is considered to be executing concurrently with respect to all the others. (Toshiko may be going off duty, after handing off all her Control Zones to Gwen, while Ianto is simultaneously logging in to Duty Station S3.)

  • A state machine can access data synchronously from other objects. (Gwen can look at Ianto’s last break time, irrespective of what Ianto is actually up to.)

  • A state machine may send a signal to another state machine to cause it to change state.

  • A state machine may respond to events sent as signals from other state machines, the outside world, or a signal requested some time in the past.

In this formulation, each object executes concurrently unless it is explicitly sequenced or synchronized with other objects. This requires the modeler to think through synchronization early, before committing to threads, tasks, processors, and so on. It also permits the implementation to be made more concurrent, because the models do not impose unnecessary or arbitrary sequencing.

Step 3: Actions

At some point, the rubber must meet the road; we must actually compute something. Each activity comprises a certain number of actions that must complete execution before the activity is completed.

Actions are expressed using an action language. There are many possible action languages; they have (almost) the same underlying building blocks. They must all, for example, provide a means to traverse associations, select and access instance data, communicate between objects, invoke external services and libraries, and perform computations on selected model data.

Our action language is designed to be easy to write, with a minimum of language elements, while remaining readable, which is a key purpose of modeling in the first place. A summary is provided in Appendix B. We discuss the pros and cons of this language later in this chapter. For now, let’s look at how it is used in our ATC example. Figure 2-5 shows the state model again, this time with actions filled in. Again, we have included annotation to explain our interpretation.

A421575_1_En_2_Fig5_HTML.gif
Figure 2-5. Air Traffic Controller actions
  • .= is an assignment. In this example, my station is an instance reference variable, valid only within the activity where it is initialized. The single . in the .= operator limits the selection to at most one instance.

  • ❷ The <class>(<attribute>:<value> ...) syntax uses the criteria in the parentheses to find matching objects. Because an identifier attribute is used in this example, one object, at most, will be found. Hence, Duty Station( ID:in.Station ) returns a reference to the Duty Station object that matches the Station number that was passed in.

  • ❸ The -> symbol specifies the immediate signaling of an event directed toward a set of instances, typically one. In this case, the Air Traffic Controller object sends the Logged in signal to itself so that it is not permanently stuck in the Logging In state. The me keyword serves as a reference to the local object (self). Note that although the signal is immediately sent, the event will not be processed until the entire activity associated with the Logging In state has completed.

  • ❹ In this case, the target of the signal is the related Duty Station object.

  • ❺ The migrate action changes the subclass of an object. Formally, this involves dissolving the generalization from the subclass instance, creating the new subclass, and reforming the relationship to the superclass. In practice, implementations find ways to store subclasses so that the formality is met efficiently (for example, using a union to store the subclass would mean that we could reuse existing memory space rather than creating a new subclass object).

  • ❻ To refer to data arriving with an event, preface it with the in keyword. In this example, in.Station refers to the station number passed in with the event.

  • ❼ The & and !& link/unlink operators create and delete an instance of the association. In this example, & /R3/my station relates itself to the station referred to in my station across R3. The / is the hop operator, which specifies a hop across a relationship. When it is not preceded by any explicit instance, navigation is assumed to start with the local instance. Note that linking/unlinking is a conceptual operation for the modeler. There are no "links" as such in xUML. What’s really going on is that the link operator is setting the local instance’s Station attribute to the value of my station.ID. We could just as easily have written Station = Duty Station(Number:in.Station).Number, but such a statement risks overlooking the concept of an association being instantiated.

  • ❽ There is no need to explicitly unlink the Duty Station, because an Off Duty Controller has no Station referential attribute and the On Duty Controller instance has been deleted.

Time and Other Details

Figure 2-6 shows the Duty Station state model and illustrates how to manage time.

A421575_1_En_2_Fig6_HTML.gif
Figure 2-6. Duty Station life cycle

There are a couple of actions to note here:

  • ❶ In this example, the Shift Specification singleton class holds a single instance with a delay value. The extra step of first assigning the singleton instance to an instance variable is instead folded into a single statement.

  • ❷ By default, a signal is immediately sent, but a delay may be specified. The delayed signal serves as a time-out, so it is canceled if the Duty Station logs out within the maximum on-duty duration.

  • UI refers not to a class, but to an external entity. An external entity is a proxy for something outside the domain boundary. In this case, the ATC domain assumes that there is a user interface (UI) that can post the warning message.

Discussion

There are many good ways to specify algorithmic computation. Figure 2-7 shows a data-flow representation of the Logging In activity.

A421575_1_En_2_Fig7_HTML.gif
Figure 2-7. Data flow diagramming an activity

Each oval in the diagram represents an action. An action may execute when all of its inputs become available. Data from sourceless arrows and class data stores (parallel lines) are available upon state entry. Dashed arrows provide no data, but pass a control token to signal completion of the source action. The Migrate, Logged In Signal, and Select actions can execute immediately upon state entry. The Write and Link actions must wait until Migrate is finished. Finally, the In Use Signal action may execute.

Data-flow notation specifies sequencing only where it is essential to the problem space. It therefore highlights opportunities for concurrent processing in the implementation. On the downside, data-flow diagrams can be difficult to draw and edit, and they may make your brain hurt as you try to comprehend sequencing.

Text-based action languages are much easier and more familiar to read, write, and edit. You can rely on the familiarity and power of your favorite text editor to get the job done. Some textual action languages make no attempt to eliminate arbitrary sequencing. Others mimic data-flow concurrency by using text symbols rather than graphical symbols. In this book, we use Scrall as a pseudo-action language, as it is as easy to edit as text and can be mapped to a data-flow representation for downstream translation. Its main elements are summarized in Appendix B.

How much of the inherent concurrency of a state activity is realized as parallel execution depends on the translation mechanism and the target platform. We are targeting a platform that has only a single processor core, so no real parallel execution is possible. A more capable target platform allows the translation mechanism to arrange how the concurrency in the model is realized as parallel execution.

Why not just write the actions in C directly? The whole point of this type of modeling is to capture the logic of the problem in an implementation-independent fashion. We want to specify actions in terms of non-C concepts such as object state machine communication, data access via compound relationships, and instance set manipulation. By keeping all model facets, class, state, and actions at the same level of abstraction, we have a single consistent set of rules and increase the opportunities during translation to choose a wider variety of efficient implementations. This also makes the modeling easier by concentrating on the logic of the processing without having to consider all the details of programming language syntax and semantics.

Executing the Model

Now that all three facets of our example application are modeled, we can execute them as an integrated unit to verify correct behavior. This can (and should) be done prior to writing or generating any code. A complete description of the execution rules can be found in the Executable UML books mentioned earlier in this chapter. They are also summarized in Appendix A. Here, we just want to give you a feel for how the models can be executed by walking through a simple scenario.

For this scenario, we will attempt to activate an Off Duty Controller by logging in to an available Duty Station. Assume that ATC53 is in the Off Duty state and that the Duty Station to be selected, DS3, is waiting in the Available state. A Ready for Duty( DS3 ) event will be addressed to ATC53 to kick things off. The value DS3 is passed as the desired Duty Station number. The choice of Duty Station happens outside our system, and our models are simply told that ATC53 is attempting to use DS3. Our models must, however, ensure that certain conditions are fulfilled before allowing this to happen.

Upon receipt of the event, ATC53 makes a transition to arrive in the Verifying Adequate Break state and executes the activity upon entry into the state. The Verifying Adequate Break activity checks to see whether a sufficiently long break has been taken. Assuming it has, ATC53 signals a Log in( DS3 ) event to itself. Having completed the activity, ATC53 then receives that same Log in event, matches it to an outgoing transition, and proceeds to the Logging In state.

ATC53 executes the Logging In activity that results in its migration from off to on duty (delete off-duty subclass instance and create on-duty subclass instance referring to the same superclass instance), linking of the new ATC53 on-duty subclass instance to DS3, and logging the current time and the signaling, this time of two events: ATC53 signals a Logged in event to itself and sends an In use event to DS3. The signaling occurs in no particular order, as would be obvious only from the DFD.

Now we have two pending events, each of which will be consumed, again, in no required order. When the Logged in event is processed by ATC53, it transitions to the On Duty state. When DS3 consumes the In Use event, it transitions to the In Use state and addresses a Max shift exceeded event to itself, delayed by the Max shift duration as indicated in the singleton Shift Specification instance. In essence, a time-out is established so that if the On Duty ATC does not take a break, the delayed event will fire and trigger a warning in the Max Shift Exceeded state.

At this point, the scenario is complete. ATC53 has successfully logged in at Duty Station DS3. Notice that the state models and actions specify behavior for nonspecific instances that are interpreted during runtime by individual instances consuming events and traversing from one state to the next.

Our scenario conveniently sidesteps the possibility of an instance consuming an event in a given state for which no transition is specified. This situation is resolved through the construction of a state table, which is required for each state model. A state table shows how an instance reacts if an unexpected event arrives, or if an expected event arrives either when the instance is ready for the event or when it is not ready for the event. Chapter 3 covers state tables in detail.

Standard Action Languages

We distinguished between elaboration and translation approaches in Chapter 1. When the UML came into existence, elaboration was king—no one saw the need for an action language. But a few people persevered, and some years later, UML finally has an action language, the Action Language for Foundational UML, or Alf. The specification can be found on the Object Management Group website ( www.omg.org ).

The specification is some 439 pages long—longer than this book. We have no wish to teach you the details of that language, or any other language for that matter. Rather, we wish to use the concepts of an action language to show how translation works. Accordingly, we have used an invented informal language that we hope can be understood intuitively with minimum effort. We describe this language in Appendix B.

Using an informal language for execution is clearly peculiar, at best. But the alternative is to teach you another language, which is not the purpose of this book. Moreover, we wish to expose the steps required to get from models to code. Consequently, we formalize the actions in later chapters. It may look as if we are writing the code twice. We’re not. We’re simply bypassing the details of a formal language.

Summary

We’ve introduced a simple application as a fuzzy and incomplete set of requirements and cast it into a concrete and executable set of models. The models are executable with a lean set of execution rules, and those rules make it possible to step through and test application scenarios in much the same way you would step through running code. The execution rules and semantics are organized into three facets: a single class model, a state model for each class, and interesting behavior and actions within each state corresponding to modeled data, modeled control, and modeled computation, respectively. The models are constructed in this sequence to minimize refactoring.

What we have not done is include in this model any implementation concepts. We have coordinated state machines by sending signals, but we have not said how those signals are sent; we’ve said we have associations between instances of classes, but we have not said how they are implemented either. As we said in Chapter 1, exclusion is neither the removal of that detail, nor the deprecation of it. The implementation is critically important; it is the subject of this book.

From here on in, our focus is on translation. We will map these model elements, along with the execution behavior defined by the modeling language, into a platform-specific bundle of C code that will run on a computing device supported by our target platform. When we focus on code production, we will not question the application requirements or try to expand or modify the application scope. Instead, we’ll assume that the modelers knew what they were doing, code the models as they were given to us, get it running in a testable environment, and move on to the next application. If the models don’t cover the requirements, neither will the code!

Footnotes

1 “When I use a word”, Humpty Dumpty said in rather a scornful tone, “it means just what I choose it to mean—neither more nor less.” “The question is,” said Alice, “whether you can make words mean so many different things.” “The question is,” said Humpty Dumpty, “which is to be master—that’s all.” —Lewis Carroll

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset