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.
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.
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.
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.
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.
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.
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
|
«Capsule» instance «Capsule» class |
Port
|
«Port» instance «ProtocolRole» class |
Connector
|
«Connector» (link) AssociationClass «Protocol» class |
Role
|
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.
Software Architectures and Documentation
Part I. Software Architecture Viewtypes and Styles
The Module Viewtype
Styles of the Module Viewtype
The Component-and-Connector Viewtype
Styles of the Component-and-Connector Viewtype
The Allocation Viewtype and Styles
Part II. Software Architecture Documentation in Practice
Advanced Concepts
Documenting Software Interfaces
Documenting Behavior
Choosing the Views
Building the Documentation Package
Other Views and Beyond
Rationale, Background, and Design Constraints
References