Guideline: Design Package
A Design Package is a construct used to partition the design model. This guideline explains how to identify and specify Design Packages.
Relationships
Related Elements
Main Description

Introduction

The Design Model can be structured into smaller units to make it easier to understand. By grouping Design Model elements into packages and subsystems, then showing how those groupings relate to one another, it is easier to understand the overall structure of the model. Note that a design subsystem is modeled as a component that realizes one or more interfaces; for more information, see Artifact: Design Subsystem and Guideline: Design Subsystem. Design packages, on the other hand, are just for grouping.

Package Content Visibility

A class contained in a package can be public or private. A public class can be associated by any other class. A private class can be associated only by classes contained in the package.

A package interface consists of a package's public classes. The package interface (public classes) isolates and implements the dependencies on other packages. In this way, parallel development is simplified because you can establish interfaces early on, and the developers need to know only about changes in the interfaces of other packages.

Package-Partitioning Criteria

You can partition the Design Model for a number of reasons:

  • You can use packages and subsystems as order, configuration, or delivery units when a system is finished.
  • Allocation of resources and the competence of different development teams may require that the project be divided among different groups at different sites. Subsystems, with well-defined interfaces, provide a way to divide work between teams in a controlled, coordinated way, allowing design and implementation to proceed in parallel.
  • Subsystems can be used to structure the design model in a way that reflects the user types. Many change requirements originate from users; subsystems ensure that changes from a particular user type will affect only the parts of the system that correspond to that user type.
  • In some applications, certain information should be accessible to only a few people. Subsystems let you preserve secrecy in areas where it is needed.
  • If you are building a support system, you can, using subsystems and packages to give it a structure similar to the structure of the system to be supported. In this way, you can synchronize the maintenance of the two systems.
  • Subsystems are used to represent the existing products and services that the system uses (for example, COTS products, and libraries), as explained in the next several sections.

Packaging Boundary Classes

When the boundary classes are distributed to packages there are two different strategies that can be applied; which one to choose depends on whether or not the system interfaces are likely to change greatly in the future.

  • If it is likely that the system interface will be replaced, or undergo considerable changes, the interface should be separated from the rest of the design model. When the user interface is changed, only these packages are affected. An example of such a major change is the switch from a line-oriented interface to a window-oriented interface.

Diagram described in accompanying text.

If the primary aim is to simplify major interface changes, the boundary classes should be placed in one (or several) separate packages.

  • If no major interface changes are planned, changes to the system services should be the guiding principle, rather than changes to the interface. The boundary classes should then be placed together with the entity and control classes with which they are functionally related. This way, it will be easy to see what boundary classes are affected if a certain entity or control class is changed.

Diagram described in accompanying text.

To simplify changes to the services of the system, the boundary classes are packaged with the classes to which they are functionally related.

Mandatory boundary classes that are not functionally related to any entity- or control classes, should be placed in separate packages, together with boundary classes that belong to the same interface.

If a boundary class is related to an optional service, group it with the classes that collaborate to provide the service, in a separate subsystem. The subsystem will map onto an optional component which will be provided when the optional functionality is ordered.

Packaging Functionally Related Classes

A package should be identified for each group of classes that are functionally related. There are several practical criteria that can be applied when judging if two classes are functionally related. These are, in order of diminishing importance:

  • If changes in one class' behavior and/or structure necessitate changes in another class, the two classes are functionally related.

Example

If a new attribute is added to the entity class Order, this will most likely necessitate updating the control class Order Administrator. Therefore, they belong to the same package, Order Handling.

  • It is possible to find out if one class is functionally related to another by beginning with a class - for example, an entity class - and examining the impact of it being removed from the system. Any classes that become superfluous as a result of a class removal are somehow connected to the removed class. By superfluous, we mean that the class is only used by the removed class, or is itself dependent upon the removed class.

Example

There is a package Order Handling containing the two control classes Order Administrator and Order Registrar, in the Depot Handling System. Both of these control classes model services regarding order handling in the depot. All order attributes and relationships are stored by the entity class Order, which only exists for order handling. If the entity class is removed, there will be no need for the Order Administrator or the Order Registrar, because they are only useful if the Order is there. Therefore, the entity class Order should be included in the same package as the two control classes.

Diagram described in accompanying text.

Order Administrator and Order Registrar belong to the same package as Order, because they become superfluous if Order is removed from the system.

  • Two objects can be functionally related if they interact with a large number of messages, or have an otherwise complicated intercommunication.

Example

The control class Task Performer sends and receives many messages to and from the Transporter Interface. This is another indication that they should be included in the same package, Task Handling.

  • A boundary class can be functionally related to a particular entity class if the function of the boundary class is to present the entity class.

Example

The boundary class, Pallet Form, in the Depot Handling System, presents an instance of the entity class Pallet to the user. Each Pallet is represented by an identification number on the screen. If the information about a Pallet is changed, for example, if the Pallet is also given a name, the boundary class might have to be changed as well. Pallet Form should therefore be included in the same package as Pallet.

  • Two classes can be functionally related if they interact with, or are affected by changes in, the same actor. If two classes do not involve the same actor, they should not lie in the same package. The last rule can, of course, be ignored for more important reasons.

Example

There is a package Task Handling in the Depot Handling System, which includes, among other things, the control class Task Performer. This is the only package involved with the actor Transporter, the physical transporter that can transport a pallet in the depot. The actor interacts with the control class Task Performer via the boundary class Transporter Interface. This boundary class should therefore be included in the package Task Handling.

Diagram described in accompanying text.

Transporter Interface and Task Performer belong to the same package since both of them are affected by changes in the Transporter actor.

  • Two classes can be functionally related if they have relationships between each other (associations, aggregations, and so on). Of course, this criterion cannot be followed mindlessly, but can be used when no other criterion is applicable.
  • A class can be functionally related to the class that creates instances of it.

These two criteria determine when two classes should not be placed in the same package:

  • Two classes that are related to different actors should not be placed in the same package.
  • An optional and a mandatory class should not be placed in the same package.

Evaluating Package Cohesion

First, all elements in a package must have the same optionality: there can be no optional model elements in a mandatory package.

Example

The mandatory entity class Article Type has, among other things, an attribute called Restock Threshold. The restock function, however, is optional in the system. Therefore, Article should be split up into two entity classes, where the optional class relates the mandatory one.

A package that is considered mandatory might not depend on any package that is considered optional.

As a rule, a single package can not be used by two different actors. The reason for this is that a change in one actor's behavior should not affect other actors as well. There are exceptions to this rule, such as for packages that constitute optional services. Packages of this type should not be divided, no matter how many actors use it. Therefore, split any package, or class, that is used by several actors unless the package is optional.

All classes in the same package must be functionally related. If you have followed the criteria in the section "Find packages from Functionally Related Classes," the classes in one package will be functionally related among themselves. However, a particular class might in itself contain "too much" behavior, or relationships that do not belong to the class. Part of the class should then be removed to become a completely new class, or to some other class, which probably will belong to another package.

Example

The behavior of a control class, A, in one package should not depend too much on a class, B, in another package. To isolate the B-specific behavior, the control class A must be split into two control classes, A' and A". The B-specific behavior is placed in the new control class, A", which is placed in the same package as B. The new class A" also gets a relationship, such as generalization, to the original object A'.

Diagram described in accompanying text.

To isolate the B-specific behavior, the control class A, which lacks homogeneity, is split into two control classes, A' and A''.

Describing Package Dependencies

If a class in one package has an association to a class in a different package, then these packages depend on each other. Package dependencies are modeled using a dependency relationship between the packages. Dependency relationships help us to assess the consequence of changes: a package upon which many packages depend is more difficult to change than one upon which no packages depend.

Because several dependencies like this will be discovered during the specification of the packages, these relationships are bound to change during the work. The description of a dependency relationship might include information about what class relationships have caused the dependency. Since this introduces information that is difficult to maintain, it should be done only if the information is pertinent and of value.

Example

In the Depot Handling System there is a dependency relationship from the package Order Handling to the package Item Handling. This association arises because the entity class Order in Order Handling has an association to the entity class Item Type in the other package.

Diagram described in accompanying text.

The package Order Handling is dependent on Item Handling, because there is an association between two classes in the packages.

Evaluating Package Coupling

Package coupling is good and bad: good, because coupling represent re-use, and bad, because coupling represents dependencies that make the system harder to change and evolve. Some general principles can be followed:

  • Packages should not be cross-coupled (i.e. co-dependent); e.g. two packages should not be dependent on one another.

Diagram described in accompanying text.

In these cases, the packages need to be reorganized to remove the cross-dependencies.

  • Packages in lower layers should not be dependent upon packages in upper layers. Packages should only be dependent upon packages in the same layer and in the next lower layer.

Diagram described in accompanying text.

In these cases, the functionality needs to be repartitioned. One solution is to state the dependencies in terms of interfaces, and organize the interfaces in the lower layer.

  • In general, dependencies should not skip layers, unless the dependent behavior is common across all layers, and the alternative is to simply pass-through operation invocations across layers.
  • Packages should not depend on subsystems, only on other packages or on interfaces.