3.2 Component Level Design
3.2 Component Level Design
Component-level design occurs after the first iteration of architectural design has
been completed. At this stage, the overall data and program structure of the software has
been established. The intent is to translate the design model into operational software.
What Is A Component?
Four basic design principles are applicable to component-level design and have been
widely adopted when object-oriented software engineering is applied.
The Liskov Substitution Principle (LSP). “Subclasses should be substitutable for their
base classes”. This design principle, originally proposed by Barbara Liskov, suggests that
a component that uses a base class should continue to function properly if a class derived
from the base class is passed to the component instead. LSP demands that any class
derived from a base class must honor any implied contract between the base class and
the components that use it. In the context of this discussion, a “contract” is a precondition
that must be true before the component uses a base class and a post condition that should
be true after the component uses a base class.
The Release Reuse Equivalency Principle (REP). “The granule of reuse is the granule
of release”. When classes or components are designed for reuse, there is an implicit
contract that is established between the developer of the reusable entity and the people
who will use it. The developer commits to establish a release control system that supports
and maintains older versions of the entity while the users slowly upgrade to the most
current version. Rather than addressing each class individually, it is often advisable to
group reusable classes into packages that can be managed and controlled as newer
versions evolve.
The Common Closure Principle (CCP). “Classes that change together belong
together.” Classes should be packaged cohesively. That is, when classes are packaged as
part of a design, they should address the same functional or behavioral area. When some
characteristic of that area must change, it is likely that only those classes within the
package will require modification. This leads to more effective change control and
release management.
The Common Reuse Principle (CRP). “Classes that aren’t reused together should not
be grouped together”. When one or more classes within a package changes, the release
number of the package changes. All other classes or packages that rely on the package
that has been changed must now update to the most recent release of the package and be
tested to ensure that the new release operates without incident. If classes are not grouped
cohesively, it is possible that a class with no relationship to other classes within a package
is changed.
Cohesion
cohesion is the “single-mindedness” of a component. Lethbridge and Laganiére define a
number
of different types of cohesion
Functional. Exhibited primarily by operations, this level of cohesion occurs when a
component performs a targeted computation and then returns a result.
Layer. Exhibited by packages, components, and classes, this type of cohesion occurs
when a higher layer accesses the services of a lower layer, but lower layers do not access
higher layers.
Communicational. All operations that access the same data are defined within one class.
In general, such classes focus solely on the data in question, accessing and storing it.
Coupling
Coupling is a qualitative measure of the degree to which classes are connected to one
another. As classes (and components) become more interdependent, coupling increases.
An important objective in component-level design is to keep coupling as low as is
possible.
Class coupling can manifest itself in a variety of ways. Lethbridge and Laganiére define
the following coupling categories:
Content coupling. Occurs when one component “surreptitiously modifies data that is
internal to another component”.
Common coupling. Occurs when a number of components all make use of a global
variable. Although this is sometimes necessary, common coupling can lead to
uncontrolled error propagation and unforeseen side effects when changes are made.
Control coupling. Occurs when operation A() invokes operation B() and passes a control
flag to
B. The control flag then “directs” logical flow within B. The problem with this form of
coupling is that an unrelated change in B can result in the necessity to change the meaning
of the control flag that A passes. If this is overlooked, an error will result.
Stamp coupling. Occurs when ClassB is declared as a type for an argument of an
operation of ClassA. Because ClassB is now a part of the definition of ClassA, modifying
the system becomes more complex.
Data coupling. Occurs when operations pass long strings of data arguments. The
“bandwidth” of communication between classes and components grows and the
complexity of the interface increases. Testing and maintenance are more difficult.
Routine call coupling. Occurs when one operation invokes another. This level of
coupling is common and is often quite necessary. However, it does increase the
connectedness of a system.
Type use coupling. Occurs when component A uses a data type defined in component
B. If the type definition changes, every component that uses the definition must also
change.
Inclusion or import coupling. Occurs when component A imports or includes a package
or the content of component B.
The following steps represent a typical task set for component-level design, when it is
applied for an object-oriented system.
Step 1. Identify all design classes that correspond to the problem domain. Using the
requirements and architectural model, each analysis class and architectural component is
elaborated.
Step 2. Identify all design classes that correspond to the infrastructure domain.
These classes are not described in the requirements model and are often missing from the
architecture model, but they must be described at this point.
Step 3. Elaborate all design classes that are not acquired as reusable components.
Elaboration requires that all interfaces, attributes, and operations necessary to implement
the class be described in detail. Design heuristics (e.g., component cohesion and
coupling) must be considered as this task is conducted.
Step 3a. Specify message details when classes or components collaborate. The
requirements model makes use of a collaboration diagram to show how analysis classes
collaborate with one another. As component-level design proceeds, it is sometimes useful
to show the details of these collaborations by specifying the structure of messages that
are passed between objects within a system. Although this design activity is optional, it
can be used as a precursor to the specification of interfaces that show how components
within the system communicate and collaborate.
Step 3c. Elaborate attributes and define data types and data structures required to
implement them. In general, data structures and types used to define attributes are
defined within the context of the programming language that is to be
Step 3d. Describe processing flow within each operation in detail. This may be
accomplished using a programming language-based pseudocode or with a UML activity
diagram. Each
software component is elaborated through a number of iterations that apply the stepwise
refinement concept.
Step 4. Describe persistent data sources (databases and files) and identify the classes
required to manage them. Databases and files normally transcend the design description
of an individual component. In most cases, these persistent data stores are initially
specified as part of architectural design. However, as design elaboration proceeds, it is
often useful to provide additional detail about the structure and organization of these
persistent data sources.