Notations for C&C Styles
Notations for C C Styles
Practitioners document C&C architectures in various ways, although most depend on informal box-and-line diagrams. In this section, we present more rigorous strategies for documenting C&C views in Acme, an architecture description language, and in UML. Focusing on architectural structure, we explain how to document a C&C view in terms of the core concepts: components, connectors, systems, properties, and styles.
4.7.1 Informal Notations
Most informal box-and-arrow diagrams of architectures are in fact attempts to represent C&C views, although C&C views are not merely boxes and lines but rather represent computational models and the basis for analytical methods. Following some guidelines, however, can lend rigor to the process.
Within a graphical depiction, each component type should be given a separate presentation form. Similarly, each connector type should be given a separate visual form. In both cases, the types should be listed in a key. However, it is important to specify what those visual forms mean. A common source of ambiguity in most existing architectural documents is the meaning of connectors, especially the use of arrows on connectors. What exactly does the "directionality" mean? Flow of data? Flow of control?
4.7.2 Formal Notations
While informal notations are often useful in the early stages of working out the documentation of a C&C architectural view, they have a number of limitations. Most importantly, different people may interpret their meaning in quite different ways. Moreover, they are usually not a good basis for detailed analytical evaluation, or tool-supported creation, maintenance, and analysis. In the remainder of this section we consider alternative, more formal notations.
ADLs and Acme
Listing 4.1 shows a partial textual description of the simple pipe-and-filter system of Figure 4.1 written in Acme, a typical architecture description language (ADL). Acme is representative of a family of ADLs that treat an architecture as an annotated graph of components and connectors. Each of the top-level component and connector instances has a corresponding definition containing its type, instance name, and substructure. The types are declared in the PipeFilter family, which is Acme's name for a C&C style. The attachments of ports to roles are also described explicitly. Components and connectors may be associated with a set of properties, each of which has a name and a value. Details of the style definition, the substructure of the pipes, properties of the pipes and connectors, and the details of the MergeAndSort component are not included here; Section 4.10 cites references to that information.
Listing 4.1 Partial textual description of the simple Pipe-and-Filter system
Family PipeFilter = { Port Type OutputPort; Port Type InputPort; Role Type Source; Role Type Sink; Component Type Filter; Connector Type Pipe = { Role src : Source; Role snk : Sink; Properties { latency : int; pipeProtocol: String = . . . ; } }; }; System simple : PipeFilter = { Component Splitter : Filter = { Port pIn : InputPort = new InputPort; Port pOut1 : OutputPort = new OutputPort; Port pOut2 : OutputPort = new OutputPort; Properties {. . . } }; Component Grep : Filter = { Port pIn : InputPort = new InputPort; Port pOut : OutputPort = new OutputPort; }; Component MergeAndSort : Filter = { Port pIn1 : InputPort = new InputPort; Port pIn2 : InputPort = new InputPort; Port pOut : OutputPort = new OutputPort; Representation { System MergeAndSortRep : PipeFilter = { Component Merge : Filter = {. . . }; Component Sort : Filter = {. . . }; Connector MergeStream : Pipe = new Pipe; Attachments {. . . }; }; /* end sub-system */ PropertybindingNote="Bindings associate a com- ponent's external interfaces with interfaces of components internal to it." Bindings { pIn1 to Merge.pIn1; pIn2 to Merge.pIn2; pOut to Sort.pOut; }; }; }; Connector SplitStream1 : Pipe = new Pipe; Connector SplitStream2 : Pipe = new Pipe; Connector GrepStream : Pipe = new Pipe; Attachments { Splitter.pOut1 to SplitStream1.src; Grep.pIn to SplitStream1.snk; Grep.pOut to GrepStream.src; MergeAndSort.pIn1 to GrepStream.snk; Splitter.pOut2 to SplitStream2.src; MergeAndSort.pIn2 to SplitStream2.snk; }; }; /* end system */
Connectors are first-class entities in Acme, having types, such as Pipe. They may also have nontrivial semanticsfor example, as defined by a protocol of interaction, represented in Acme as a particular type of connector property. Moreover, connectors have "interfaces," which identify the roles in the interaction and may associate semantics with those interfaces. The Filter and Pipe types have many instances. Note that different instances of a component or connector type may have quite different behavior: Here we have five components of type Filter, each performing a different kind of computation. The Splitter filter has two output ports. Bindings associate the input and output ports of the MergeAndSort filter with the input ports of Merge and the output port of Sort, respectively. The purpose of a binding is to provide a logical associationnot a communication pathas a binding does not have any specific runtime behavior of its own.
Comparing the Acme description to the informal graphical diagram shown earlier, one might wonder whether there are advantages to using such a text-based approach. Although the textual format tends to make the topological and graphical nature of the architecture less perspicuous, it has a number of advantages. Most important, the text is inherently more expressive. While, in principle, you can say anything you want using graphical forms, to do this for complex system properties requires a lot of special-purpose symbolic notation that is typically hard to learn and use, and that clutters the visual depiction. Consequently what people typically do is take a shortcut, allowing free-form annotationswhich is (surprise!) after all a textual form, and not a very good one at that. In particular, such free-form notations are difficult to use as the basis of formal analysis.
Using a textual form, such as Acme, does not preclude the complementary use of graphical renditions. Indeed, virtually all ADLs have accompanying tools that allow one to view and modify C&C architectural views through a graphical interface.
Finally, comparing C&C documentation in an ADL (such as Acme) to the use of other more generic graphical and textual notations (such as UML, described below) reveals that the ADL provides a much more constrained world for describing architectural models. This has the advantage of providing concepts and notation tailor-made to architectures. For example, Acme allows one to explicitly define C&C styles and to treat connectors as first-class design entities. On the other hand, general-purpose design notations allow more flexibility in terms of the kind of elements and relations one can model, are usually better supported by commercial tools, and are often more widely understood in the software engineering community.
UML
There is no single preferred strategy in UML to document C&C views. Rather, UML offers a number of alternatives for documenting C&C views, and each alternative has its own advantages and disadvantages. Here we present three strategies for using UML to model components and connectors. We organize the presentation around the choices for representing component types and instances, as the components are typically the central design elements of an architectural description. For each choice, we consider subalternatives for the other architectural elements.
The three strategies are (1) representation of component types by UML classes and component instances by objects, (2) representation of component types as UML subsystems and component instances as subsystem instances, and (3) use of a UML profile providing a variant on the first strategy. Each of the strategies has strengths and weaknesses, depending on how well it supports the selection criteria.
- Semantic match: The strategy should respect documented UML semantics and the intuitions of UML modelers. The interpretation of the encoding UML model should be close to the interpretation of the component-and-connector viewtype description so the model is intelligible to both designers and UML-based tools. In addition, the mapping should produce legal UML models.
- Visual clarity: The resulting architectural descriptions in UML should bring conceptual clarity to a system design, avoid visual clutter, and highlight key design details.
- Completeness: The component-and-connector types, as well as the computational model, should be representable in the UML model.
Also there is typically a trade-off between completeness and legibility. Encodings that emphasize completeness, by providing a semantic home for all the aspects of architectural design, tend to be verbose, whereas graphically appealing encodings tend to be incomplete. Hence, the strategy you pick will depend on what aspects of architectural design need to be represented. In restricted situations, such as if there is only one type of connector, it may be preferable to use an incomplete but visually appealing encoding.
Strategy 1: Using Component Types as Classes and Component Instances as Objects
A natural candidate for representing component-and-connector types in UML is the class concept. Classes describe the conceptual vocabulary of a system just as component-and-connector types form the conceptual vocabulary of an architectural description in a particular style. Additionally, the relationship between classes and objects is similar to that between architectural types and their instances. Figure 4.6 illustrates the general idea.
Figure 4.6. Types as classes and instances as objects. The Filter architectural type is represented as the UML class Filter. Instances of filters, such as Splitter, are represented as corresponding objects in an objectinstancediagram. To provide a namespace boundary, we enclose the descriptions in packages. The representation of MergeAndSort, denoted Details, is shown as another package and will be discussed in more detail later.
We now take a closer look at this strategy. The type/instance relationship in architectural descriptions is a close match to the class/object relationship in a UML model. UML classes, like component types in architectural descriptions, are first-class entities and are rich structures for capturing software abstractions. The full set of UML descriptive mechanisms is available to describe the structure, properties, and behavior of a class, making this a good choice for depicting detail and using UML-based analysis tools.
Properties of architectural components can be represented as class attributes or with associations, behavior can be described using UML behavioral models, and generalization can be used to relate a set of component types. The semantics of an instance or a type can also be elaborated by attaching one of the standard stereotypes; for example, the «process» stereotype can be attached to a component to indicate that it runs as a separate process. Note that the relationship between MergeAndSort and its substructure is indicated using a dependency relation. Note also that the typical relationship between classes and instances in UML is not identical to that between architectural components and their instances. A component instance might define additional ports not required by its type or might associate an implementation in the form of additional structure that is not part of its type's definition. In UML, an object cannot include parts that its class does not also define.
With strategy 1, ports can be represented in five ways, as shown in Figure 4.7.
- Option 1: No explicit representation. Leaving ports out leads to the simplest diagrams but suffers from the obvious problem that there is no way to characterize the names or the properties of the ports. However, this choice might be reasonable if the components have only a single port or if the ports can be inferred from the system topology, or if the diagram is refined elsewhere.
- Option 2: Ports as annotations. Representing ports as annotations provides a home for information about ports, although annotations have no semantic value in UML and hence cannot be used as a basis for analysis. Again, if the detailed properties of a port are not of concern, this approach might be reasonable.
- Option 3: Ports as class/object attributes. Treating ports as attributes of a class/object makes them part of the formal structural model, but they can have only a simple representation in a class diagram: essentially, a name and a type. This restriction limits the expressiveness of this option.
- Option 4: Ports as UML interfaces. Describing port types as UML interfaces has three advantages. First, both the interface and the port concepts characterize aspects of the ways in which an entity can interact with its environment. Second, the UML "lollipop" notation provides a compact description of a port in a class diagram depicting a component type. In an instance diagram, a UML association role, corresponding to a port instance, qualified by the interface namethe port typeprovides a compact way to designate that a component instance is interacting through a particular port instance. Finally, this approach provides visually distinct depictions of components and ports, in which ports can clearly be seen as subservient to components. However, although the two concepts are similar, they are not identical. An interface exposes a set of operations that can be invoked by the environment of a component. In contrast, the description of a port in an ADL often includes both the services provided by the component and those it requires from its environment. Furthermore, it is meaningful for a component type to have several instances of the same port type, but it is not meaningful to say that a class realizes several versions of the same UML interface. For example, there is no easy way to define a "splitter" filter type that has two output ports of the same "type" using this technique. Finally, unlike classes, UML interfaces do not have attributes or substructure.
- Option 5: Ports as classes. Describing ports as classes contained by a component type overcomes the lack of expressiveness of the previous alternatives: We can now represent port substructure and indicate that a component type has several ports of the same type. A component instance is modeled as an object containing a set of port objects. But by representing ports as classes, we not only clutter the diagram but also lose clear discrimination between ports and components. We could use a notational variation in which the ports are contained classes, as shown in the lower part of option 5 in Figure 4.7. Indicating points of interaction is counterintuitive, however, as containment usually indicates that a class owns other classes whose instances may or may not be accessible through instances of the parent class.
Figure 4.7. Five ways to represent ports. Option 1 is to avoid the issue by not representing ports explicitly. Option 2 uses annotations and is a minor extension to option 1. Option 3 treats ports as an attribute of a class or an object. Option 4 treats ports as interfaces. Option 5 turns ports into classes.
Strategy 1 offers three reasonable options for representing connectors.
- Option 1: Connector types as associations and connector instances as links. In an architectural box-and-line diagram of a system, the lines between components are connectors. One tempting way to represent connectors in UML is as associations between classes or links between objects. The approach is visually simple, provides a clear distinction between components and connectors, and makes use of the most familiar relationship in UML class diagrams: association. Moreover, associations can be labeled, and a direction associated with the connector can be indicated with an arrow in UML. Unfortunately, connectors and associations have different meanings. A system in an architectural description is built up by choosing components with behavior exposed through their ports and connecting them with connectors that coordinate their behaviors. A system's behavior is defined as the collective behavior of a set of components whose interaction is defined and limited by the connections between them. In contrast, although an association, or link, in UML represents a potential for interaction between the elements it relates, the association mechanism is primarily a way of describing a conceptual relationship between two elements. In addition, associations are relationships between UML elements, so an association cannot stand on its own in a UML model. Consequently, a connector type cannot be represented in isolation. Instead, one must resort to naming conventions or the use of stereotypes whose meaning is captured by description in UML's object constraint language. Further, the approach does not allow one to specify the interfaces to the connector, that is, its roles.
- Option 2: Connector types as association classes. One solution to the lack of expressiveness is to qualify the association with a class that represents the connector type. In this way, the attributes of a connector type or a connector can be captured as attributes of a class or an object. Unfortunately, this technique still does not provide any way of explicitly representing connector roles. The approach is similar to the one taken in the UML Real-Time profile, which we consider later.
- Option 3: Connector types as classes and connector instances as objects. One way to give connectors first-class status in UML is to represent type as class and connector instances as objects. Using classes and objects, we have the same options for representing roles as we had for ports: not at all, as annotations, as interfaces realized by a class, or as child classes contained by a connector class. Given a scheme for representing ports and roles, an attachment between a port and a role may be represented as an association or a dependency.
In addition to representing individual components and connectors and their types, we also need to encapsulate graphs of components and connectors: systems. Three options are available.
- Option 1: Systems as UML subsystems. The primary mechanism in UML for grouping related elements is the package. In fact, UML defines a standard package stereotype, called «subsystem», to group UML models that represent a logical part of a system. The choice of subsystems is appropriate for any choice of mappings of components and connectors and works particularly well for grouping classes.
One of the problems with using subsystems, as defined in UML 1.4, is that although subsystems are both a classifier and a package, the meaning is not entirely clear. Some people have argued that we should be able to treat a subsystem as an atomic classlike entity at certain stages in the development process and later be able to refine it in terms of more detailed substructure. Having the ability to do this would make the subsystem construct more appropriate for modeling architectural components.
- Option 2: Systems as contained objects. Object containment can be used to represent systems. Components are represented as instances of contained classes, and connectors are modeled using one of the options outlined earlier. Objects provide a strong encapsulation boundary and carry with them the notion that each instance of the class will have the associated "substructure."
However, this approach has problems. The most important one is that associations, used to model connectors between contained classes, are not scoped by the class. That is, it is not possible to say that a pair of classes interacts via a particular connector, modeled as an association, only in the context of a particular system. So, for example, indicating that two contained classes interact via an association is valid for instances of those classes used anywhere else in the model.
- Option 3: Systems as collaborations. A set of communicating objects connected by links is described in UML using a collaboration. If we represent components as objects, we can use collaborations to represent systems. A collaboration defines a set of participants and relationships that are meaningful for a given set of purposes, which in this case is to describe the runtime structure of the system. The participants define classifier roles that objects play, or conform to, when interacting. Similarly, the relationships define association roles that links must conform to.
Collaboration diagrams can be used to present collaborations at either the specification or the instance level. A specification-level collaboration diagram shows the roles, defined within the collaboration, arranged in a pattern to describe the system substructure. An instance-level collaboration diagram shows the objects and links conforming to the roles at the specification level and interacting to achieve the purpose. Therefore, a collaboration presented at the instance level is best used to represent the runtime structure of the system.
Figure 4.8 illustrates this approach. Although this is a natural way to describe runtime structures, it leaves no way to explicitly represent system-level properties. There is also a semantic mismatch; a collaboration describes a representative interaction between objects and provides a partial description, whereas an architectural configuration is meant to capture a complete description.
Figure 4.8. Systems as collaborations. The Filter architectural type is represented as previously. Instances of Filters and Pipes are represented as corresponding classifier rolesfor example, /Splitter indicates the Splitter roleand association roles, and the objects and links conforming to those roles are shown in the collaboration diagram at the instance level, indicated by underlines on the names.
Strategy 2: Using Subsystems
The second strategy for using UML to model components and connectors is to use UML subsystems. This approach is appealing because packages are an ideal way to describe coarse-grained elements as a set of UML models. Also the package construct is already familiar to UML modelers as a way of bundling pieces or views of a system. Figure 4.9 shows the filter type as a package, and filter instances as package instances.
Figure 4.9. Components as subsystems
The subsystem construct is used in UML to group, or encapsulate, a set of model elements that describe a logical piece of a system, similar to components in architectural descriptions. Subsystemsindeed, any packagecan include structures based on any of the UML models. The advantage over describing components and connectors as classes is that by identifying a component or a connector with a package, we can include structure as classes, or objects and behavioral models. This approach also has a visual appeal; substructure can be depicted as "embedded" in the package. Components and component types would be modeled in essentially the same way, although one could also take advantage of the UML template mechanism when defining a type.
However, the use of subsystems to model components suffers from a number of problems. In UML, a subsystem has no behavior of its own, so all communications sent to a closed subsystem must be redirected to instances inside the subsystem, and UML leaves that redirection unspecified as a semantic variation point. Second, subsystem interfaces raise the same set of issues mentioned for class interfaces. (That is, it is impossible to model several interfaces of the same type on the same subsystem.) Third, representing substructure, such as ports, as elements contained by a subsystem is arguably counterintuitive. The fact that certain elements correspond to ports, others to properties, and others to representations is likely to be misleading.
This scheme provides two natural choices for representing connectors: as dependenciesvisually simple but lacking expressivenessor as subsystems themselves. Dependencies have visual appeal, but they do not provide a way to define more detailed aspects of a connector. Using subsystems to model connectorssimilar to using objects or classes to model connectors in the previous two approachessuffers from the problem that components and connectors are not distinguishable.
Strategy 3: Using the UML Real-Time Profile
Thus far, we have examined ways to encode architectural concepts in generic UML. We now consider a different approach. Rather than using generic UML, we start by leveraging the work done in defining a specific UML profilenamely, the UML Real-Time (UML-RT) profile. A UML profile is a collection of stereotypes, constraints, and tagged values that can be bundled to form a domain-specific language specialization.
UML-RT, a profile originally developed by the telecommunication industry to meet its software development needs, benefits from a rich pool of commercial experience. In particular, UML-RT adopts the notion of a connector between components as a protocol. Unlike generic UML, the profile provides a natural home for expressing runtime structures, and supplies a semantic mapping to UML. It also is supported by commercial tools.
In UML-RT, the primary unit for encapsulating computation is the capsule. Capsules can have interfaces and can be hierarchically decomposed. Component types map to UML capsule-stereotyped classes; component instances map to capsule-stereotyped objectsin a collaboration diagram.
Component ports map to UML-RT ports, because both serve as interfaces that define points of interaction between the computational elements and the environment. Port instances map to UML port-stereotyped objects. Port types could likewise be mapped to port-stereotyped implementation classes, but a UML-RT protocol role defines the type of the port. Instead, we can map port types to protocolRole-stereotyped classes in UML.
Connectors map to UML-RT connectors because both represent interactions between the computational units. Connector types map to the UML AssociationClasses, and connector instances map to UML links, instances of UML association. UML-RT protocols represent the behavioral aspects of UML-RT connectors.
Systems describe the structural configuration, as do UML-RT collaborations. Thus, systems map to collaborations.
Table 4.7 summarizes the relationship between UML-RT and the concepts of the C&C viewtype. To illustrate this mapping, Figure 4.10 shows the simple pipe-and-filter system of Figure 4.1, but now drawn in UML-RT, using the strategy just outlined. In Figure 4.10, the filters become capsules of type Filter, each with input and output ports. A slash prepending the name denotes a role in a collaboration. The pipes become connectors that conform, in this case, to a pipe protocol (ProtPipe) with a source and a sink protocol role. The output and input Acme ports, joined by the connector, therefore play the source and sink protocol roles, respectively. Because a UML-RT port plays a specific role in some protocols, the protocol role defines the type of the port, which simply means that the port implements the behavior specified by that protocol role. Thus, pOut's type is ProtPipe::source, and pIn's type is ProtPipe::sink. For visual simplicity, only two of the port instances are labeled.
Figure 4.10. UML-RT description for system simple. The filter type is defined as a capsule, a class stereotype. The system consists of three top-level capsule instances, one of which is further decomposed into two sub-capsules.
C&C | UML-RT |
---|---|
Component
Type |
«Capsule» instance «Capsule» class |
Port
Type |
«Port» instance «ProtocolRole» class |
Connector
Type (Behavioral constraint) |
«Connector» (link) AssociationClass «Protocol» class |
Role
Type |
No explicit mapping; implicit elements: LinkEnd AssociationEnd |
System | Collaboration |
For binary protocols, UML-RT provides notational conventions for the port icon and the type name. The role selected as the base protocol rolein this case, the source roleis shown as a black-filled box, with the type denoted only by the protocol name; the other, conjugate role is shown as a white-filled box, with the type denoted by appending ~ to the protocol name, as shown in Figure 4.10.
The collaboration diagram is presented at the specification level to indicate how the capsules participate in the system. The filter representing MergeAndFilter is shown as a capsule class instead of a capsule role for a similar reason: to convey a pattern of interaction for the internal capsules. Finally, the bindings from the external port to the internal port are shown as normal connectors.
Because only one Filter type is in the simple PipeFilter system, only one class is in the class diagram shown in Figure 4.10. In UML-RT, all elements contained by a capsule are considered attributes of that capsule class, and all attributes have protected visibility except ports, which have public visibility, indicated by + on the port attribute. Additionally, ports are listed in a separately named compartment. The «capsule»-stereotyped Filter class has four ports: two as sources and two as sinks. The reason is that each Filter has either one or two ports of each type, so two are defined to accommodate all Filter instances, whereas only the used ports are shown in the collaboration diagram. The connectors in the collaboration diagram do not have a counterpart in the class diagram, because the connectors associate the Ports, not the Filter.
Conclusions
The current definition of UML does not favor a single best way to document C&C views. Each strategy has certain strengths and weaknesses, and in practice you are likely to see all of them. All of the strategies exhibit some form of semantic incompleteness or mismatch. The key stumbling blocks are difficulties in faithfully representing ports, connectors, and substructure. With respect to ports the primary difficulty is to support the definition of multiple ports of the same type. With respect to connectors, the primary difficulty is to support definition of connector types independent of any particular use of them. With respect to substructure, the primary difficulty is to be able to limit the scope of the substructure definition to the element being elaborated.
In the final analysis, UML can be made to work, typically by sacrificing completeness in the diagram, and making up for it in supporting documentation. A reasonable alternative is to use a profile, such as UML-RT, which, although nonstandard, provides a better match to the architectural documentation task.