This guideline explains how to structure your component model to ensure that the components are:
· Highly cohesive
· Loosely coupled
· Well isolated
· Of the right granularity
· Layered according to their generality
Your selection of an architectural pattern to follow has a strong influence on how you structure your
component model. While this guideline covers how to structure components using the layering technique, layering is only
one of many possible architectural patterns upon which to base your structuring activities.
By following this guideline, you define a number of well structured, logical components and their responsibilities.
The concept of assigning responsibilities to components was made popular through the CRC
(Classes-Responsibilities-Collaborations) technique [WIRFS-BROCK90]. Responsibilities are defined as:
· The knowledge a component maintains
· The actions a component performs
You may define the components using a modeling tool, or drawings in a word processing document. Figure 1 depicts an
example of a UML Component Relationship Diagram created using this technique.
Figure1. Component Relationship
Diagram
To structure your component model, assess the components according to a number of attributes. These attributes help you
asses the overall quality of a component.
Cohesion
Cohesion is a measure of how well a component's responsibilities are related to each other. High cohesion (components
with closely related responsibilities) is good, while low cohesion is bad.
An example of a highly cohesive component might be a 'Dictionary' component that has the responsibilities of checking
spelling and performing a thesaurus function to find alternatives for words. If the 'Dictionary' component also has the
responsibility for performing numeric arithmetic, then it exhibits low cohesion. It would be better for that
responsibility to be dealt with by a different component. The following are seven degrees of cohesion, listed from
highest to lowest:
-
Functional: Operations all contribute to the execution of one and only one problem related
task.
-
Sequential: Operations are involved in activities such that output data from one activity
serves as input data to the next.
-
Communicational: Operations contribute to activities that use the same input, or output data.
-
Procedural: Operations are involved in different, and possibly unrelated activities, which
flows from one activity to the next.
-
Temporal: Operations are involved in activities that are related in time.
-
Logical: Operations contribute to activities of the same general category; the activities to
be executed are selected externally.
-
Coincidental: Operations have no meaningful relationship to each other.
Coupling
Coupling is an indication of the strength of the associations between components. Strongly coupled components have
tightly bound associations, and the components are highly dependent on each other. Weakly coupled components have very
loose (or even non-existent) associations with each other.
Weakly coupled components are better than tightly coupled ones, because it is easier to switch one component for
another, or update a component without affecting others. There are six degrees of coupling, listed following from best to worst:
-
Data coupling: Communication is via parameters, where each parameter is an elementary piece of
data.
-
Stamp coupling: Communication is via composite data, or data with meaningful internal
structure.
-
Control coupling: Data passed is intended to control the internal logic of the component.
-
Common coupling: Components both refer to the same global data area.
-
Content coupling: One component refers to the inside of another in some way; one component
changes the data inside another.
-
Hybrid coupling: Different meanings are assigned to different parts of a range of data. For
example, a flag is both a data flag and a control flag simultaneously.
Isolation
Isolation is a measure of the degree to which product or technology dependencies are isolated from each other. There
are two extremes of isolation:
-
Bad isolation: Every component has a dependency on the product or technology of other
components. There is little to no use of patterns that encourage isolation techniques.
-
Good isolation: Product and technology dependencies are fully decoupled. There is good use of
patterns that encourage isolation techniques. Examples of such patterns include the Gang of Four "Proxy",
"Bridge", and "Mediator" patterns and the GRASP "Indirection" pattern.
Isolation and coupling are closely related. Isolation of products and technologies ensures loose coupling. Layering is
another approach to ensuring good isolation.
Granularity
Granularity is a measure of the size, or amount of functionality, assigned to a component. There are five levels of
granularity:
-
Very fine grained: For example, an object-oriented language class useful for assembling
distributed components, but not considered a component in its own right.
-
Fine grained: A software element that can be called at runtime, with a clear interface and a
separation between interface and implementation. Also known as a distributed component.
-
Medium grained: An autonomous business concept, or business process. Also known as a business component.
-
Coarse grained: A set of cooperating business components assembled to deliver a solution to a
business problem. Also known as a system-level component.
-
Very course grained: For example, a federation of system-level components working together to
provide some business value. It helps heterogeneous information systems interoperate.
You can think of a system-level component as the same as an application. However, one major difference is that a
component-based system is made up of components visible at runtime. The implementation of a component can be changed
without having to change the rest of the system. Making such changes is more difficult with large, monolithic
applications. Different component-based systems (applications) can be assembled without necessarily having to redesign
at the detail level, break code apart, recompile, or re-link the system.
Layering
Layering involves:
-
Identifying suitable architectural layers within which components can be placed.
-
Placing components (and subsystems) into these layers according to their generality and functionality.
-
Defining rules for how the layers can interact with each other.
Bachmann et al [BACHMANN00] offer the following definition of layering. "Layering, like all architectural structures, reflects a division of the software
into units. In this case, the units are layers; each layer represents a virtual machine. A virtual machine is a
collection of software that together provides a cohesive set of services that other software can utilize without
knowing how those services are implemented. ...The goal of layering is to
define virtual machines that are small enough to be well understood, but comprehensive enough so that likely changes
will affect only a single layer".
Layering is a mechanism for grouping a set of components according to their generality. For example, a system might
have the following layers:
-
All components that provide application-independent business
function. Application-independent business functions are things like customer management and product
management, which apply to many applications.
-
All components that provide service functions, such as error
handling and audit. These components are both business- and application-independent.
-
Middleware components, such as message queuing and relational DBMS
software.
Layering offers the following benefits [BACHMANN00]:
-
Layers help to bring quality attributes of modifiability and portability to a system. A change to a lower layer
that does not affect its interface will not require a change to a higher layer. For example, any J2EE compliant
application server that conforms to the J2EE standard may be freely substituted without change to
application-level software. A change to a higher layer that does not affect what it requires from lower layers
will not affect a lower layer. In general, changes to a layered software system that do not affect an interface
are confined to a single layer. Thus, layers define units of reuse and portability.
-
Layers are part of the blueprint role that architecture plays for constructing the system. By knowing which
layers contains their software, developers know what services they can rely on in the coding environment.
Layers may define work assignments for development teams.
-
Layers are part of the communication role played by architecture. In a large system, the number of dependencies
among modules expands rapidly. Organizing the software into layers with interfaces is an important tool to help
you manage complexity and communicate the structure to developers.
-
Layers help with the analysis role played by architecture. They can be used for analyzing the impact of changes
to the design.
Layering can be strict or non-strict. A strict layering scheme means that components can only use components in the
same layer, or layers, immediately below them. A non-strict layering scheme means components can use components in the
same, or any lower layer. As a general rule, components should not use components in upper layers. If components have
dependencies on components in higher layers, then it is difficult to replace the upper layer components without
changing the lower layer components.
There are many ways of layering software; Figure 2 shows one possible set of layers. You may need fewer or more layers,
depending on the size and complexity of your system. However, avoid schemes with ten or more layers, as they may be
overly complex.
Figure 2. Software layers
When defining layers, describe the responsibilities of each layer. For example, in Figure 2:
-
The DialogueControl layer handles user-system interactions and logic.
-
The BusinessProcessing layer contains application-specific services that handle functional
requirements logic and choreography.
-
The BusinessServices layer contains more general business components that may be used in
several applications.
-
The Middleware layer contains components such as interfaces to databases and
platform-independent operating system services.
-
The SystemSoftware layer contains components such as operating systems and databases.
Layers are not the same as tiers. Tier pictures express allocation to
machines in a distributed environment, data flow among elements, and the presence and utilization of communication
channels. These diagrams are similar to layer diagrams, but tier diagrams tend to show two-way arrows indicating
bi-directional communication. Bi-directional communication is discouraged in a layer diagram.
Furthermore, assignment of a component to a tier is defined by the required service level characteristics of the
system. The main difference between layer diagrams and tier diagrams is that the former has no notion of placement,
while the latter does. Figure 3 illustrates the differences between layers and tiers.
Figure 3. Layers and tiers
|