Guideline: Design Subsystem
This guideline explains how to identify and specify Design Subsystems.
Relationships
Related Elements
Main Description

Identifying Subsystems

A complex analysis class is mapped to a design subsystem if it seems to embody behavior that cannot be the responsibility of a single design class acting alone. A complex design class might also become a subsystem, if it is likely to be implemented as a set of collaborating classes.

Subsystems also are a good means of identifying parts of the system that are to be developed independently by a separate team. If the collaborating design elements can be completely contained within a package along with their collaborations, a subsystem can provide a stronger form of encapsulation than that provided by a simple package. The contents and collaborations within a subsystem are completely isolated behind one or more interfaces, so that the client of the subsystem is only dependent upon the interface. The designer of the subsystem is then completely isolated from external dependencies.  The designer (or design team) is required to specify how the interface is realized, but they are completely free to change the internal subsystem design without affecting external dependencies. In large systems with largely independent teams, this degree of de-coupling combined with the architectural enforcement provided by formal interfaces is a strong argument for the choice of subsystems over simple packages.

The design subsystem is used to encapsulate these collaborations in such a way that clients of the subsystem can be completely unaware of the internal design of the subsystem, even as they use the services provided by the subsystem. If the participating classes/subsystems in a collaboration interact only with each other to produce a well-defined set of results, the collaboration and its collaborating design elements need to be encapsulated within a subsystem.

This rule can be applied to subsets of collaborations as well. Anywhere part or all of a collaboration can be encapsulated and simplified, doing so will make the design easier to understand.

The following table provides hints to use to identify subsystems.



Hint

Details

Look for optionality If a particular collaboration (or sub-collaboration) represents optional behavior, enclose it in a subsystem. Features which might be removed, upgraded, or replaced with alternatives need to be considered independent.
Look to the user interface of the system.
  1. If the user interface is relatively independent of the entity classes in the system (that is, the two can and will change independently), create subsystems which are horizontally integrated. Group related user interface boundary classes together in a subsystem, and group related entity classes together in another subsystem.
  2. If the user interface and the entity classes it displays are tightly coupled (for example, a change in one triggers a change in the other), create subsystems which are vertically integrated.  Enclose related boundary and entity classes in common subsystem.
Look to the Actors
  1. Separate functionality used by two different actors, because each actor might independently change their requirements on the system.
  2. Create subsystems to encapsulate access to an external system or device.
Look for coupling and cohesion between design elements Highly coupled or cohesive classes/subsystems collaborate to provide some set of services. Organize highly coupled elements into subsystems, and separate elements along lines of weak coupling. In some cases, weak coupling can be eliminated entirely by splitting classes into smaller classes with more cohesive responsibilities, or repartitioning subsystems appropriately
Look at substitution If there are several levels of service specified for a particular capability (example: high, medium and low availability), represent each service level as a separate subsystem, each of which will realize the same set of interfaces. By doing so, the subsystems are substitutable for one another.
Look at distribution Although there can be multiple instances of a particular subsystem, each executing on different nodes, in many architectures it is not possible for a single instance of a component to be split across nodes. In the cases where subsystem behavior must be split across nodes, it is recommended that you decompose the subsystem into smaller subsystems (each representing a single component) with more restricted functionality.   Determine the functionality that must reside upon each node and create a new subsystem to 'own' that functionality, distributing the responsibilities and related elements of the original subsystem appropriately.   The new subsystems are internal to the original subsystem.


Modeling Subsystems

Design Subsystems are modeled using UML components stereotyped as <<subsystem>>. This construct provides the following modeling capabilities:

  • can group classes to define a larger granularity part of a system
  • can separate the visible interfaces from internal implementation
  • can have execution at run-time

Some other considerations are:

  • Each Design Subsystem must be given a name and a short description.
  • The responsibilities of the original analysis class need to be transferred to the newly-created subsystem, using the description of the subsystem to document the responsibilities

Subsystems that Represent Existing Products

Where an existing product is one that exports interfaces, that is, operations (and perhaps receptions), but otherwise keeps all details of implementation hidden, then it can be modeled as a subsystem.  Examples of products the system uses that you might be able to represent by a subsystem include:

  • Communication software (middleware).
  • Database access support (RDBMS mapping support).
  • Application-specific products.

Some existing products such as collections of types and data structures (for example, stacks, lists, and queues) might be better represented as packages, because they reveal more than behavior, and it is the particular contents of the package that are important and useful and not the package itself, which is simply a container. 

Common utilities, such as math libraries, could be represented as subsystems if they simply export interfaces.  Whether this is necessary or makes sense depends on the designer's judgment about the nature of the thing modeled.  Subsystems are object-oriented constructs (as they are modeled components): a subsystem can have instances (if the designer so indicates). 

When defining the subsystem to represent the product, also define one or more interfaces to represent the product interfaces.

Subsystem Dependency Restrictions

Design Subsystems (modeled as UML components with <<subsystem>> stereotype) differ from packages in their semantics.  A subsystem provides behavior through one or more interfaces which it realizes. Packages provide no behavior; they are simply containers of things which provide behavior.

The reason for using a subsystem instead of a package is that subsystems encapsulate their contents, providing behavior only through their interfaces. The benefit of this is that, unlike a package, the contents and internal behaviors of a subsystem can be changed with complete freedom so long as the subsystem's interfaces remain constant. Subsystems also provide a 'replaceable" design element.  Any two <<realization>> components that realize the same interfaces (or <<specification>> component) are interchangeable.

In order to ensure that subsystems are replaceable elements in the model, a few rules need to be enforced:

  • A subsystem needs to minimize exposing its contents. Ideally, no element contained by a subsystem has 'public' visibility, and thus no element outside the subsystem depends on the existence of a particular element inside the subsystem. Some exceptions are as follows:
    • In some technologies, the externals of a subsystem cannot be modeled as a UML interface. For example, a Java interface is modeled as a stereotyped class.
    • The subsystem design might require exposing classes rather than UML interfaces. For example, a "delegate" or "access" class can be used to hide a complex collaboration of other classes. While an ordinary package could be used instead, a subsystem could be used in order to emphasize the intent to encapsulate behavior and hide internal details.

  • When a subsystem's externals are not UML interfaces, it often is helpful to have a diagram (for example named "External View") that shows the visible elements of the subsystem.
  • A subsystem needs to define its dependencies on subsystem interfaces (and publicly visible elements of subsystems in the exceptional cases described above). In addition, a number of subsystems might share a set of interfaces or class definitions in common, in which case those subsystems 'import' the contents of the packages which contain the common elements. This is more common with packages in lower layers in the architecture, to ensure that common definitions of classes which must pass between subsystems are consistently defined.

Subsystem Specification and Realization

Definition

The UML 2.1.1 Superstructure specification supports separate definitions of component specification and realization.  Briefly, <<specification>> denotes: 

A classifier that specifies a domain of objects without defining the physical implementation of those objects. For example, a Component stereotyped by <<specification>> will only have provided and required interfaces, and is not intended to have any realizingClassifiers as part of its definition.

And, <<realization>> denotes:

A classifier that specifies a domain of objects and that also defines the physical implementation of those objects. For example, a Component stereotyped by <<realization>> will only have realizing Classifiers that implement behavior specified by a separate <<specification>>Component.

The separation of specification and realization allows for two separate descriptions of the subsystem. The specification serves as a contract that defines everything that a client needs to know to use the subsystem. The realization is the detailed internal design intended to guide the implementer. If you need to support multiple realizations, create separate "realization" subsystems and draw a realization from each realization subsystem to the specification subsystem.

When and how to use

If the internal state and behavior of the subsystem are relatively simple, it can be sufficient to specify the subsystem by its exposed interfaces, state diagrams to describe the behavior, and descriptive text.

For more complex internal state and behavior, analysis classes can be used to specify the subsystem at a high level of abstraction. For large systems of systems, the specification of a subsystem might also include use cases.

Providing a detailed specification separate from the realization tends to be most useful in the following situations:

  • The subsystem realization's internal state or behavior is complex, and the specification needs to be expressed as simply as possible in order for clients to use it effectively;
  • The subsystem is a reusable "assembly component" intended for assembly into a number of systems;
  • The subsystem's internals are expected to be developed by a separate organization;
  • Multiple implementations of the subsystem need to be created;
  • The subsystem is expected to be replaced with another version that has significant internal changes without changes to the externally visible behavior.

Maintaining a separate specification takes effort, however, as one must ensure that the realization of the subsystem is compliant with the specification. The criteria for when and if to create separate specification and realization classes and collaborations needs to be clearly defined.

Dependencies

A specification needs to define its dependencies. These are the interfaces and visible elements from other subsystems and packages that must be available in all compliant realizations of the subsystem.

A realization might have additional dependencies, introduced by the designer or implementer. For example, there might be an opportunity to use a utility component to simplify the implementation, but the use of this utility component is a detail that need not be exposed to clients. These additional dependencies can be captured on a separate diagram as part of the realization.

Relationship to Implementation

A fully detailed specification defines everything a client needs to use the subsystem. This means refining the exposed interfaces and any publicly visible elements so that they are one-to-one with code. Leave any analysis classes that were introduced to specify the subsystem behavior as high level abstractions, because they are intended to be independent of any subsystem's realizations.

More Information
Concepts