Table 1.1 summarizes the discussion in this section of the elements, relations, and properties of the module viewtype.
|Elements||The element of a module view is a module, which is an implementation unit of software that provides a coherent unit of functionality.|
|Relations||Relations shown in a module view are a form of is part of, depends on, or is a.
|Properties of elements||Properties of a module include the following:
|Properties of relations||
|Topology||The module viewtype has no inherent topological constraints.|
System designers use the term module to refer a variety of software structures, including programming language units, such as Ada packages, Modula modules, Smalltalk or C++ classes, or simply general groupings of source code units. In this book, we adopt a broad definition.
A module is an implementation unit of software that provides a coherent unit of functionality.
We characterize a module by enumerating a set of responsibilities, which are foremost among a module's properties. This broad notion of "responsibilities" is meant to encompass the kinds of features that a unit of software might provide.
Modules can both be aggregated and decomposed. Different module views may identify a different set of modules and aggregate or decompose them based on different style criteria. For example, the layered style identifies modules and aggregates them based on an allowed-to-use relation, whereas the generalization view identifies and aggregates modules based on what they have in common.
The module viewtype has the following relations:
As we will see in Section 10.2, properties are documented as part of the supporting documentation for a view. The list of properties pertinent to a set of modules will depend on many things but is likely to include the following:
In a view documenting an is-part-of relation, some of the interfaces of the submodules exist for internal purposes only; that is, the interfaces are used only by the submodules within the enclosing parent module. These interfaces are never visible outside that context and therefore do not have a direct relationship to the parent interfaces.
Different strategies can be used for those interfaces that have a direct relationship to the parent interfaces. The strategy shown in Figure 1.1(a) is encapsulation in order to hide the interfaces of the submodules. The parent module provides its own interfaces and maps all requests, using the capabilities provided by the submodules. However, the facilities of the enclosed modules are not available outside the parent.
Figure 1.1. (a) Module C provides its own interface, hiding the interfaces of modules A and B; (b) Module C exposes a subset of the interfaces of modules A and B as its interface.
Alternatively, the interfaces of an aggregate module can be a subset of the interfaces of the aggregate. That is, an enclosing module simply aggregates a set of modules and selectively exposes some of their responsibilities. Layers and subsystems are often defined in this way. For example, if module C is an aggregate of modules A and B, C's implicit interface will be a subset of the interfaces of modules A and B (see Figure 1.1(b)).
- Mapping to code units. This identifies the files that constitute the implementation of a module. For example, a module ALPHA, if implemented in C, might have several files that constitute its implementation: ALPHA.c, ALPHA.h, ALPHA.oif precompiled versions are maintainedand perhaps ALPHA_t.h to define any data types provided by ALPHA.
- Test information. The module's test plan, test cases, test scaffolding, test data, and test history are important to store.
- Management information. A manager may need the location of a module's predicted completion schedule and budget.
- Implementation constraints. In many cases, the architect will have a certain implementation strategy in mind for a module or may know of constraints that the implementation must follow. This information is private to the module and hence will not appear, for example, in the module's interface.
Styles in the module viewtype may have properties of their own in addition to these. Also, you may find other properties useful that are not listed.
COMING TO TERMS
We have used the term substitutability to explain the meaning of the generalization relationship between two modules. We have relied on an intuitive notion of being able to use one module in place of another: In principle, users of the substituted module should not be able to observe any differences in behavior from the original module.
But this informal notion of substitutability begs the question of what we mean by "differences in behavior." This phrase might be interpreted in many ways. For example, if B is substitutable for A, we might mean any of the following, among others.
In the preceding progression, the definition of substitutability becomes stronger at each step, moving from syntactic properties to semantic properties to quality attributes.
Which definition is the "right" one? Any of these might be reasonable, but you need to be clear which you mean. The implications for documentation are that when you use a style in which generalization is one of the relations, you should state what kind of substitutability is intended.