By taking the elements and the properties of the module viewtype and focusing on the is-part-of relation, we get the module decomposition style. You can use this style to show how system responsibilities are partitioned across modules and how those modules are decomposed into submodules. Unlike other styles of the module viewtype, decomposition features fairly weak restrictions on the viewtype itself but is usefully distinguished as a separate style, for several reasons.
First, almost all architectures begin with the module decomposition style. Architects tend to attack a problem with divide-and-conquer techniques, and a view rendered in this style records their campaign. Second, a view in this style is a favorite tool with which to communicate the broad picture of the architecture to newcomers. Third, this style begins to address the modifiability that will be built into the architecture by allocating functionality to specific places in the architecture.
The criteria used for decomposing a module into smaller modules depend on the purpose of the decomposition:
A decomposition view may represent the first pass at a detailed architectural design; the architect may subsequently introduce other style-based specializations and evolve the view resulting from decomposition into a more detailed use, layered, or other module-based view in some other style.
2.1.2 Elements, Relations, and Properties
Table 2.1 summarizes the discussion of the characteristics of the decomposition style. Elements of the decomposition style are modules, as described in Section 1.2. Certain aggregations can be called subsystems. The principal relation, the decomposition relation, is a specialized form of the is-part-of relation and has as its primary constraint the guarantee that an element can be a part of at most one aggregate.
The decomposition relation may have a visibility property, which defines whether the submodules are visible to only the aggregate modulethe parentor also to other modules. A module is said to be visible if it can be used by other modules. With this property, an architect has some control over the visibility of modules, as illustrated in Figure 1.1. A decomposition relation in which no contained module is visible outside its parent is sometimes called a containment relation. In a decomposition relation, loops are not allowed; that is, a module cannot contain any of its ancestors. No module in a decomposition view can have more than one parent.
|Elements||Module, as defined by the module viewtype. A module that aggregates other modules is sometimes called a subsystem.|
|Relations||The decomposition relation, which is a refined form of the is-part-of relation. A documentation obligation includes specifying the criteria used to define the decomposition.|
|Properties of elements||As defined by the module viewtype.|
|Properties of relations||Visibility, the extent to which the existence of a module is known, and its facilities are available, to those modules outside its parent.|
2.1.3 What the Decomposition Style Is For and What It's Not For
A decomposition style view presents the functionality of a system in intellectually manageable pieces that are recursively refined to convey more and more details. Therefore, this style is well suited to support the learning process about a system. Besides the obvious benefit for the architect to support the design work, this style is an excellent learning and navigation tool for newcomers in the project or other people who do not necessarily have the whole functional structure of the system memorized. The grouping of functionality shown in this style also builds a useful basis for defining configuration items within a configuration management framework.
The decomposition style most often serves as the input for the work assignment view of a system, which maps parts of a software system onto the organizational units, or teams, that will be given the responsibility for implementing and testing them. A decomposition view also provides some support for analyzing effects of changes at the software implementation level, but because this view does not show all the dependencies among modules, you cannot expect to do a complete impact analysis. Here, views that elaborate the dependency relationships more thoroughly, such as the module uses style described later, are required.
2.1.4 Notations for the Decomposition Style
In informal notations, modules in the decomposition style are usually depicted as named boxes that contain other named boxes. Containment can also be shown using indentation, as in Figure 2.2.
Figure 2.2. The decomposition of the A-7E software architecture results in three modules and is-part-of relations (Bass, Clements, Kazman, 2001, p. 61).
The nesting notation can use a thick border suggesting opaquenessand explained in the keyindicating that children are not visible outside the parent. Similarly, various kinds of arcs can be used to indicate containment, or nonvisibility, as opposed to an ordinary is-part-of relation. If a visual notation is not available for indicating visibility, it can be defined textually, as is done for other properties, especially the modules' responsibilities.
In UML, the subsystem construct can be used to represent modules that contain other modules; the class box is normally used for the leaves of the decomposition. Subsystems are both a package and a classifier. As a package, they can be decomposed and hence are suitable for the aggregation of modules. As a classifier, they encapsulate their contents and can provide an explicit interface.
In UML, aggregation is depicted in one of three ways:
Figure 2.1. In UML, aggregation may be shown by (a) nesting, with the aggregate module shown as a package, or by (b) using arcs between the parent and the children. The solid diamond indicates the parent module.
Other properties, such as the modules' responsibilities, are given textually, perhaps using an annotation.
2.1.5 Relation to Other Styles
It is possible, and often desirable, to map between a module decomposition view and a component-and-connector view. We discuss this in greater detail later. For now, it is sufficient to say that the point of providing such a mapping is to indicate how the software implementation structures map onto runtime structures: generally, a many-to-many relationship. The same module might implement several components or connectors. Conversely, one component might require several modules for its implementation. The mapping may be fairly straightforward or quite complex.
The decomposition style is closely related to the work assignment style, a member of the allocation viewtype. The work assignment style maps modules resulting from a decomposition to a set of teams responsible for implementing and testing those modules.
2.1.6 Examples of the Decomposition Style
Appendix A contains an example of a module decomposition view for NASA's ECS system.
A-7E Avionics System
An example of the decomposition style comes from the A-7E avionics software system described in Bass, Clements, and Kazman 1998, Chapter 3. Figure 2.2 shows the graphical part of the view. The figure names the elements and shows the is-part-of relation among them for the A-7E system.
Except for the modules' names, however, the figure shows none of the properties associated with this style. Supporting the figure is textual documentation that explains the decomposition criteria and for each module lists
In this example, the criterion for decomposition is the information-hiding principle, which holds that there should be a module to encapsulate the effects each kind of change considered likely. A module's responsibilities, then, are described in terms of the information-hiding secrets it encapsulates.
In A-7E, the first-order decomposition produced three modules: hardware hiding, behavior hiding, and software decision hiding. Each of these modules is decomposed into two to six submodules, which are in turn decomposed, and so forth, until the granularity is fine enough to be manageable. A useful design heuristic holds that a module is small enough if it could be discarded and begun again if the programmer(s) assigned to implement it left the project.
The A-7E module view documentation describes the responsibilities of the three highest-level modules as follows:
Following is how the documentation describes the decomposition of the Software Decision Module into second-level modules. Unless otherwise indicated, a module is visible outside its parent:
The Data Banker provides values for all data that report on the internal state of a module or on the state of the aircraft. The Data Banker also signals events involving changes in the values that it supplies. The Data Banker is used as long as consumer and producer are separate modules, even when they are both submodules of a larger module. The Data Banker is not used if consumers require specific members of the sequence of values to be computed by the producer, or if a produced value is solely a function of the values of input parameters given to the producing procedure (such as sin(x)). The Data Banker is an example of the use of the blackboard architectural style. The choice among updating policies should be based on consumers' accuracy requirements, how often consumers require the value, the maximum wait that consumers can accept, how rapidly the value changes, and the cost of producing a new value. This information is part of the specification given to the implementor of the Data Banker.
In the case of the A-7E architecture, this second-level module structure was enshrined in many ways: Design documentation, online configuration-controlled files, test plans, programming teams, review procedures, and project schedule and milestones all were pegged to this second-level module structure as their unit of reference. If you use a module decomposition structure to organize your project, you need to pick a level of the hierarchy as was done here, based on a granularity of modules that is manageable. The module guide describes a thirdand in some cases a fourthlevel of decomposition, but that has been omitted here.
Mil-Std 498 CSCIs and CSCs
Readers familiar with U.S. military software standards, such as MIL-STD-498 and MIL-STD-2167A, will recognize that CSCIs (Computer Software Configuration Items), and CSCs (Computer Software Components) constitute a decomposition view of a system and nothing more. A CSCI is an aggregation of software that satisfies an end use function and is designated for separate configuration management by the acquirer. CSCIs are selected based on trade-offs among software function, size, host or target computers, developer, support concept, plans for reuse, criticality, interface considerations, the need to be separately documented and controlled, and other factors. A CSC is a distinct part of a CSCI and may be further decomposed into other CSCs and CSUs (Computer Software Units).
COMING TO TERMS
When documenting a module view of a system, you may choose to identify certain aggregated modules as subsystems. A subsystem can be pretty much anything you want it to be, but it often describes a part of a system that (1) carries out a functionally cohesive subset of the overall system's mission, (2) can be executed independently, and (3) can be developed and deployed incrementally. An air traffic control system, for example, may be divided into the following areas of capability:
Each of these areas might reasonably be called a subsystem. Informally, a subsystem refers to a system portion that can be usefully considered separately from the other portions.
But not just any portion of a system will do. At a minimum, a subsystem must exhibit some coherent, useful functionality. More than that, however, the term also suggests a portion of the system that can execute more or less independently and that directly supports the system's overall purpose. In our air traffic control application, for example, a math utilities library is certainly a portion of a system and an aggregation of modules and even has coherent functionality. But the library is unlikely to be called a subsystem, because it lacks the ability to operate independently to do work that's recognizably part of the overall system's purpose.
Subsystems do not partition a system into completely separate parts, because some parts are used in more than one subsystem. For example, suppose that the air traffic control system looks like this:
In this case, a subsystem consists of one segment from the top layer, as well as any segments of any lower layers that it needs in order to carry out its functionality. A subset of the system formed in this way is often called a slice, or a vertical slice.
The "more or less independent" nature of a subsystem makes it ideal for dividing up a project's work. You may, for example, ask an analyst to examine the performance of a subsystem. If a user's interaction with a system can be confined to a subsystem, its security properties become important. A subsystem can often be fielded and accomplish useful work before the whole system is complete. A subsystem makes a convenient package to hand off to a team or a subcontractor to implement. The fact that it executes more or less independently allows that team to work more or less independently even through testing. An arbitrary module, by contrast, can certainly be assigned to a team for implementation, but it probably requires the presence of other modules to see it through testing.
The UML world has co-opted the term subsystem to mean something quite specific: an aggregation of elements that exhibits behaviorthe collective behavior of the aggregated elementsand possibly offering one or more interfacesrealized by the interfaces of the aggregated elements. According to the UML specification:
The observation that a subsystem has no behavior or interface of its own except for that of its aggregated parts corresponds to Figure 1.1(b). In UML, the notation for subsystems is based on the package construct. Any of the following are correct:
You may decide to identify subsystems in your design. If you do, make sure that your rationale explains why you chose the ones you did and what you plan to do with them.