Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Web Development

Building fully traceable models


Jun01: Integrating CMOS with UML

Mark is a software engineer at Motorola and Terry is president of Software Engineering Excellence. They can be contacted at [email protected] and [email protected], respectively.


The Coats-Mellon Operational Specification (CMOS) has been in use since 1994. The goal of the method is to provide a rigorous, yet easy, way to define system behavior early in the software-development process.

But there is more to system development than defining system behavior. Most CMOS users we know have applied CMOS in the context of some much broader software engineering development process such as the Rational Unified Process (RUP), while at the same time using additional modeling languages such as the Unified Modeling Language (UML).

CMOS graphical constructs are simple, few in number, and easy to draw and read. But because of the lack of CMOS-specific tools, most CMOS users turn to simple tools such as Microsoft Word or Visio for CMOS diagrams. However, if these same users use other tools for other diagrams (which is normally the case) it can be difficult to maintain a cohesive and fully traceable model.

Given that, the modeling notation war is over, with UML being the winner — and given the plethora of tools that support UML, the next obvious refinement of CMOS is to translate its notation to UML. This is one objective of this article. The other — and more important — objective is to show where the methods of CMOS can best be used in the context RUP. Process and methods are, after all, more important than notation.

CMOS Meets UML and RUP

The RUP is a configurable process framework. Here, we follow a field-proven configuration of RUP that incorporates the methods of CMOS. Not surprisingly, this configuration calls for multiple iterations per development cycle. We will discuss only a single, representative iteration, and only those steps in the process that involve CMOS will be addressed. Each iteration in the process begins with these steps:

1. Define the use cases for the iteration. (In general, it is a set of scenarios from various use cases that is allocated to an iteration, but for simplicity we employ here a small set of small use cases and each is treated as a whole.)

2. For each use case allocated to the iteration, define:

  • 2.1. The events.

  • 2.2. The actor-system interaction.

  • 2.3. The view of participating classes (VOPC).

3. Define the subsystem structure models.

4. Define the subsystem behavior models.

5. Define subsystem support classes.

6. Verify traceability.

Steps 1 and 2.1 are concerned with the problem domain, Steps 2.3 through 5 are concerned with the solution domain, and Steps 2.2 and 6 are concerned with both. CMOS, being a behavioral analysis tool, can be applied in all of Step 2, with Step 2.2 being at the heart of the method.

CMOS has five types of diagrams: actor, actor inheritance, event category, actor event, and system response. The first three can be represented using UML use case diagrams, and the rest using UML activity diagrams. To illustrate, we will use the ATM example used in our previous article "Constructing Operational Specifications" (DDJ, June 1995).

Defining Use Cases for the Iteration

Step 1 is used to define the initial set of use cases. It is possible to discover more use cases as each use case is elaborated through the remaining steps. The first three diagrams in CMOS are the actor diagram, the actor inheritance diagram, and the event category diagram. Collectively these diagrams are used to scope the system under consideration and to summarize event flow at the highest level. The actor diagram defines all of the actors that are involved with the system, event flow relationships between those actors, and event flow relationships between the system and those actors. The actor inheritance diagram defines generalization relationships between actors. The event category diagram defines generalization relationships between events and to some extent categorizes the events. Figure 1 shows all three of these diagram types for a section of the ATM example from the June 1995 CMOS article. (A complete set of CMOS/UML diagrams for this article is available electronically; see "Resource Center," page 5.)

The information captured by this set of diagrams can be represented by a single UML diagram type — the use case diagram. Use case diagrams define actors, use cases, and the relationships between them. It is appropriate to think of a use case as a category for a series of related events. Categorizing events with use cases is necessary to simplify the organization and management of events. Figure 2 is a use case diagram for the ATM example; it replaces the actor diagram and the actor inheritance diagram. Use cases are represented as ovals on use case diagrams.

Actors involved with a given use case are connected to that use case with straight lines; these lines can optionally have arrowheads to show who initiates the iteration. Perform Transaction is an example of a use case. It has relationships with actors and other use cases. Inside each use case is a series of events. In this example, Withdraw, Deposit, and Retrieve Balance are considered types of transactions so each has a generalization relationship with Perform Transaction. The generalization between Card User and Service Tech shows how CMOS actor inheritance can be represented in UML.

Use Case for the Iteration

The main purpose of Step 2.1 is to provide an initial set of events for building the diagrams in the next step. Start by identifying the obvious events. An initial set of events for each use case is in Figure 3. This also shows how a use case diagram can be used to replace a CMOS event category diagram. Only use cases are used (the actors are omitted) in this particular application of a use case diagram because its sole purpose is to categorize events with use cases. In theory, it is acceptable to combine the results of this step with the previous one, resulting in a single use case diagram. In practice, such a diagram would almost always be too cluttered. When new events are discovered during other activities, this diagram should be updated accordingly.

Defining Actor-System Interaction

Use case technology and CMOS are two different but closely related ways of specifying system behavior. System behavior is most succinctly defined as how and when a system reacts (to events). In CMOS, "how" is specified by system response diagrams and "when" is specified by actor event diagrams. Our primary reason for creating CMOS was the recognition that many developers find it advantageous, as well as natural, to base problem/system analysis on the identification of events (see the discussion of event partitioning in Essential Systems Analysis, by S.M. McMenamin and J.F. Palmer, Yourdon Press, 1984, ISBN 0-13-287905-0). The greater the number of possible events and/or the greater the amount of asynchronicity, the greater the appeal of this approach. Thus, in CMOS the first diagram type used in Step 2.2 is the actor event diagram, a diagram that shows what possible events are being thrown at the system and in what possible sequences.

Translating CMOS Actor Event Diagrams into UML

CMOS has its own notation for actor event diagrams (for more details, see the June 1995 article). What we will examine here is how to use UML activity diagrams for the same purpose. Figures 4, 5, and 6 show actor event specifications for the use case Perform Transaction, Deposit, and Withdraw, respectively. In these diagrams, activities are used to represent events. In UML terms, these activities (that is, the ones without stereotypes) are action states. (Recall that an activity is a special case of a state, and that an action state is shorthand for a state with an entry action only and whose outgoing transitions are generally all of the completion type. Action states may be presented as ordinary states or as activities.) And because action states are atomic and complete in negligible time, we feel justified in using them to represent the CMOS concept of an event.

CMOS sequence bars are modeled as swimlanes (swimlanes have no inherent semantics and can be used as the modeler desires) and are always numbered 1,2,3, and so on. The main difference in presentation is that sequence bars are narrow stripes — narrower than an actor event symbol — with wider spaces between them, whereas swimlanes are wider stripes with no space between them.

CMOS sequence return symbols are modeled as action states with the stereotype <<seq return>>. The action label in such states must be the name of some sequence bar. The semantics are: Any event in the named sequence bar can be the next event. In Figure 4, the sequence return symbols in sequence bar 9 specify that either of the events in sequence bar 6 can be the next event. It is also possible for a sequence return symbol to reference another actor event diagram. In Figure 5, the sequence bar 3 specifies a return to sequence bar 1 of the actor event diagram for Perform Transaction.

Figure 4 shows one way of linking actor event diagrams together. The <<specialization>> stereotype in sequence bar 8 means the action state represents an actor event specification that is a specialization (in the UML sense) of the actor event specification upon which it appears. It also means there is (or eventually will be) an actor event diagram by that name. Figure 5 is the diagram for Deposit, and Figure 6 is the diagram for Withdraw. To link diagrams that are not otherwise stereotyped, use the <<link>> stereotype.

Another commonly occurring situation when modeling event sequences is the case where a given event and the resultant sequence is common to several sequence bars. As an alternative to the brute force technique of drawing that event and the resultant sequence every place it is applicable, see the <<interrupt>> action state in bar 2 in Figure 4. The list of numbers in curly brackets after the name of the event are the numbers of the bars for which this event is applicable.

Translating CMOS System Response Diagrams into UML

Again, in CMOS the "how" aspect of behavior is specified by system response diagrams. An actor event usually has a system response, but not always. The behavior specified by a response diagram is invoked by the arrival of the corresponding actor event. CMOS has its own notation for system response diagrams (see our June 1995 DDJ article). What we will look at here is how to use UML activity diagrams for the same purpose. Figure 7 shows the system response specifications for those actor events in Figures 4, 5, and 6 for which responses were deemed appropriate. Figure 7 actually contains several diagrams — the name of a response diagram is the name of the associated event. Consider, for example, the event Bank validates PIN in Figure 4. There is a diagram with the same name in Figure 7.

When activity diagrams are used in this fashion, the activities are by default UML activity states (unlike in actor event diagrams where they are action states). The actor instances appearing on these diagrams specify object flow in the normal UML sense.

You need to recognize that specifying system response is the first step in the process involving the solution domain; that is, one is taking a position about what is or will be going on inside the system. One of the best techniques for accomplishing this daunting task is the application of patterns. One pattern that is applicable at this point is the so-called "boundary-entity-control" pattern, which first appeared in Object-Oriented Software Engineering, by Ivor Jacobson, et al. (Addison-Wesley, 1992, ISBN 0-201-54435-0) and is now part of the UML Profile for Software Development Processes in the OMG Unified Modeling Language Specification (Version 1.3, June 1999). This pattern was introduced in the context of object-oriented development and is most commonly used there. However, its concepts are abstract enough that they can be applied equally well in process-oriented development. So, for example, on system response diagrams — which are, in fact, process oriented — it is appropriate to think in terms of boundary, entity, and control activities (as opposed to, say, objects or subsystems). Thus, in Figure 7 these three concepts appear as stereotypes of activities.

The equivalent step in RUP uses UML interaction diagrams (sequence or collaboration) wherein the designer must decide not only what response is appropriate (expressed as sequences of messages), but also what things (objects or subsystems) will take on the responsibility for accepting which messages. This is a solid, field-proven approach, and one that we have used many times. But for cases where the designer is uncomfortable with the idea of inventing or finding responsible things at this point in the process, where doing so would be a distraction, or where it has already been decided that a process-oriented approach will be used for the rest of the development process, CMOS system response diagrams are probably a better choice.

Why Two Diagrams?

UML activity diagrams have been used in other contexts to support the analysis of use cases. At the highest level, they have been used to analyze the interactions among use cases. In this case, activities usually represent activity states (not action states), and the swimlanes represent use cases. At the next level of refinement, activity diagrams have been used to analyze individual use cases. The activities here also represent activity states, but swimlanes aren't used. This usage is similar to our use of activity diagrams just described. The difference is that we specify the control flow (the "when" aspect of behavior) and its associated activities (the "how" aspect of behavior) separately: the former as actor event diagrams and the latter as system response diagrams. And we use activity diagrams — a general-purpose diagram type — for both.

Again, the overriding reason for this separation of concerns is to support event-driven analysis. This is particularly useful when the use case is complex, having many actor events with nontrivial relationships between them. Sometimes the nominal path of actor events is trivial, but as more and more off-nominal paths are added, the events and their relationships become a major challenge unto themselves.

Another appealing feature of this separation of concerns is the way actor diagrams help specify events that behave like interrupts, which can occur at any time. See the previous description of the <<interrupt>> stereotype. For behavior that is mostly event/interrupt driven, UML recommends using statechart diagrams instead of activity diagrams, and one of the reasons is that statecharts have an elegant feature that can be applied in these cases — the composite state. But to create a state chart, one has to define states, which means combining concerns of events and states.

Separate actor event and system response diagrams may also be helpful when creating test cases. Actor-diagram scenarios specify test cases from the user's point of view. System response diagram scenarios specify test cases from the system's point of view. This separation of viewpoints could be essential in managing large, complex products that tend to have thousands of test cases.

Showing Concurrency

CMOS has the capability to show concurrency in actor event diagrams. Figures 8a and 8b show examples from the original DDJ CMOS article. These two diagrams show two concurrent threads that start up at the same time between sequence bars 2 and 3. Figure 8a specifies that the completion of both threads triggers the next event (the and condition). Figure 8b specifies that the first thread to complete triggers the next event (the or condition) and that the other completing thread does not trigger the next event. Figures 9a and 9b show Figures 8a and 8b expressed as activity diagrams, respectively. Because the default semantics of a complex transition with multiple inputs is and, no stereotype is need in Figure 9a — thus, the use of the <<or>> stereotype in Figure 9b.

Tracking Development Using Activities

Our article "Using the Coats-Mellon Operational Specification" (DDJ, June 1999) described a method of using system response bubbles to track development progress. If activities replace system response bubbles, the same method can be applied to the activities.

Defining the View of Participating Classes

Step 2.3 in the process begins to define the structure of the system that will be needed to implement the behavior. At some point when building any object-oriented solution, you define object classes. Each object class is given the responsibility for implementing part of the system behavior (and objects of that class will execute that behavior in the running system). By using RUP, the normally perplexing problem of deciding which classes to invent can largely be mitigated. The problem is addressed earlier in the process where objects (not classes) are invented and then classified based on (field-proven) patterns of interaction. That reduces this step to one of coalescing the instance-level decisions recorded on interaction diagrams to a structure model expressed as class diagrams. RUP recommends having one such structure model per use case and calls such a model a VOPC; that is, references to those classes in the total solution that are there to support the particular use case. (Obviously, a class does not have to be exclusive to a view.)

By using the combination of RUP and CMOS we propose here, no commitment to using object orientation has been made previous to this step, so for object-oriented development this is where it starts. At this point you can begin defining classes containing operations that correspond to certain events and activities, guided by the patterns and stereotypes used for the system response diagrams. Figure 10 shows the VOPC for the ATM example.

Some would argue that it is more appropriate to use a top-down approach to defining structure and thus define subsystems before classes. For this approach to work, you must have good reason to believe the chosen set of subsystems will be relatively viable for the current iteration and relatively stable during subsequent iterations. In the absence of such confidence, it is probably better to use the classes first (bottom-up) approach. The classes defined in the VOPCs can provide important structural insight for determining subsystems.

Defining Subsystem Structure Models

When defining subsystems (Step 3), you need to partition the VOPC classes into subsystems. A UML subsystem is a cohesive functional package that provides behavior only through interfaces (in the UML sense of an interface). This is not just a definition — it's a strong recommendation. Therefore, eventually the (public) operations of the (public) classes in each subsystem need to be organized into interfaces, which then become the only public features of that subsystem. Figure 11 is an example of what the results of these steps might look like for the ATM system.

Numerous guidelines and patterns exist for performing these steps. This topic is clearly outside the scope of this article, but for the sake of completeness, we will cover one pattern (but without the rationale). In this approach, there is generally at least one controller class per subsystem. As the control logic becomes more and more complex, additional subcontrollers may be needed. In rare cases, no controller classes at all will be needed for a particular subsystem. This might be the case for a subsystem whose sole purpose is to store and provide data. Figures 12 and 13 show the classes for two of the subsystems in Figure 11.

Defining Subsystem Behavior Models

Controller classes are typically modeled as state machines. Creating a state machine for a subsystem involves combining appropriate parts of the specifications from the actor event diagrams and system response diagrams into a set of collaborating controller classes for that subsystem. Writing code from state machines is a common and fairly straightforward practice. There are even some case tools that do this with a fair degree of completeness. At this point in the process, some controller classes will have been defined in the VPOCs and allocated to various subsystems.

It may also be necessary to define state machines for some of the supporting classes in the subsystem if their behavior is complex. Figure 14 is the state machine for the Controller class in the Card Reader subsystem. Figure 15 is the state machine for the Controller class in the ATM subsystem. In some cases, it is possible to see the activities from system response diagrams morphed into states in the state machine. In other cases, new states, such as Idle, have been added to allow for the merging of the response diagrams together to form one state machine. Also, most actor events appear as triggering events on the transitions leaving the various Idle states. This is an illustration of how the separation of actor events from system responses is beneficial even at this stage of the process.

Defining Subsystem Support Classes

This is the step (Step 5) during which you will typically determine whether to build support classes. Subsystem design is clearly outside the scope of this article, but for the sake of completeness, a few internal classes have been added to the subsystems. These so-called "support classes" are classes that contain various operations used within the subsystem to support the implementation of its interfaces. In Figure 13, StateMachine and the abstract class ATMObj are examples of such classes. They provide mechanisms for implementing state machines and for creating various types of other objects.

Verify Traceability

It should be possible to trace all of the events in all the specifications in the use cases down through the behavior diagrams, the VOPCs, and the subsystem state machines. While doing this trace, it also should be possible to determine if the structural elements (classes, subsystems, and interfaces) make sense. This is a vital sanity check that should be conducted before continuing on to the next major step, which is detailed design.

Conclusion

In this article, we've described how the concepts and constructs of CMOS can be integrated with UML and RUP. Some advantages of this integration are:

  • There is much wider tool support for UML notation than for CMOS notation — by far!

  • UML activity diagrams provide a rich enough set of concepts and constructs for expressing actor event and system response diagram concepts.

  • Both the behavioral and structural analysis results can be maintained in a single tool.

  • UML is a widely accepted standard.

  • UML use cases can provide more information about how categories of events are related.

  • When integrating CMOS with UML and RUP, there is no loss of CMOS kinds of information.

But CMOS does bring some new concepts and techniques to the table. It differs from RUP in that it (CMOS) focuses exclusively on events in the beginning. Interestingly, use case dogma dictates this same focus (commonly stated as "treat the system as a black box"), but this is rarely done and, in our opinion, to the determent of the project. The other difference is that in CMOS, the initial attempt at design (when the system is first treated as a white box) is done without the distraction of having to conjure up objects.

DDJ


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.