As a model may have hundreds (if not thousands) of model elements, how do you organize the elements that make up a system and their relationships? And how do you use this information to determine how best to develop the system while considering technical trade-offs concerning the system, including which elements may be developed in parallel, which elements may be purchased rather than built, and which elements may be reused? Packages and subsystems, called model management elements, address these questions.
A package is a grouping and organizing element in which other elements reside, which must be uniquely named. In the UML, packages are used in a manner similar to the way directories and folders in an operating system group and organize files. For example, the project management system may be decomposed into a collection of classes organized into packages as follows:
Date, time, and other utility classes
The Worker class and any other worker-related classes in which the Worker class is contained inside of a package named Generic
Generic classes such as the Worker class and any other worker-related classes
The UnitOfWork class and any other work-related classes
The WorkProduct class and any other work product-related classes
A package housing classes responsible for providing a user interface through which users may interact with the system
A package housing classes responsible for implementing business functionality
A package housing classes responsible for implementing data storage functionality
Packages allow us to partition our system into logical groups and then to relate these logical groups; otherwise, it could become overwhelming to work with every class and its relationship at once. A package is shown as a large rectangle with a small rectangle or "tab" attached to its top, left side. The packages in the previous list, together with their relationships, are shown in Figure 3-41.
You can show the name of a package inside of its large rectangle when the package contents are not shown; otherwise, when the package contents are shown in the large rectangle, you should show the name of a package inside its tab. In Figure 3-41, you see that the User Interface, Utility, and Business Processing packages don't show their contents, while all the other packages do show some of their contents. Thus, the User Interface, Utility, and Business Processing packages have their package names within the large rectangle, whereas the other packages have their names in their respective tabs. Each element inside a package may have a visibility symbol indicating whether the element is accessible from outside its package (i.e., is public). Figure 3-41 shows that the Worker, UnitOfWork, and WorkProduct classes are public. The Generic package located inside of the Workers package is also public.
A dependency from a source package to a target package indicates that the contents of the source package use the contents of the target package. Figure 3-41 shows that the Data package uses the Workers, Work Units, and Work Products packages. It also shows that the User Interface, Business Processing, and Data packages use the Utility package, while the User Interface package uses the Business Processing package, which in turn uses the Data package.
A package defines a namespace, a part of a model in which a name must be unique. An element shown in a package is most likely defined in that package if it is simply named. For example, the Work Units package in Figure 3-41 defines one public class named UnitOfWork. You can show the UnitOfWork class in other packages to indicate that those packages use the class, in which case you qualify the class name with the path to the package in which the class is defined. Such a fully qualified name is referred to as a pathname. The pathname of an element is a sequence of package names linked together and separated by double colons (::), followed by the name of the element. The sequence of package names starts from the outermost package level and works its way down to the package containing the element in question. Figure 3-41 shows that the Data package uses the following:
The Worker class located inside the Generic package, which is nested inside the Workers package
The UnitOfWork class located inside the Work Units package
The WorkProduct class located inside the Work Products package
Recall that a system is an organized collection of elements that may be recursively decomposed into smaller subsystems and eventually into nondecomposable primitive elements. For example, the project management system may be decomposed into the following:
A user interface subsystem responsible for providing a user interface through which users may interact with the system
A business processing subsystem responsible for implementing business functionality
A data subsystem responsible for implementing data storage functionality
The primitive elements would be the various classes that are used in these subsystems and ultimately in the whole system. While a package simply groups elements, a subsystem groups elements that together provide services such that other elements may access only those services and none of the elements themselves. And while packages allow us to partition our system into logical groups and relate these logical groups, subsystems allow us to consider what services these logical groups provide to one another.
A subsystem is shown as a package marked with the subsystem keyword. The large package rectangle may have three standard compartments shown by dividing the rectangle with a vertical line and then dividing the area to the left of this line into two compartments with a horizontal line. Figure 3-42 shows how a Data subsystem for our project management system might look. The subsystem's operations, specification elements, and interfaces describe the services the subsystem provides, and are the only services accessible by other elements outside the subsystem.
The upper-left compartment shows a list of operations that the subsystem realizes. The lower-left compartment may be labeled "Specification Elements" and shows specification elements that the subsystem realizes. For example, any use cases that the subsystem provides are specification elements that the subsystem must realize. The right compartment may be labeled "Realization Elements" and shows elements inside the subsystem that realize the subsystem's operations and specification elements as well as any interfaces that the subsystem provides. You can modify this general notation by rearranging compartments, combining compartments, or completely suppressing one or more compartments. Any element may be used as a specification or realization element, because a realization simply indicates that the realization element supports at least all the operations of the specification element without necessarily having to support any attributes or associations of the specification element.
Figure 3-43 uses subsystems to refine Figure 3-41. The Business Processing and Data packages from Figure 3-41 are now subsystems. The Business Processing subsystem provides an interface that is used by the User Interface package. The Business Processing subsystem itself uses the Data subsystem and the IProducible interface provided by the Data subsystem. The Data subsystem realizes the IProducible interface, which is outside the subsystem itself, various operations, and the Manage Project use case that was discussed in Chapter 2. The use case is the oval in the specification element's compartment. The realization elements of the Data subsystem realize the read, destroy, and doWork operations, the use case, and the operations of the IProducible interface.
Notice in Figure 3-43 that the User Interface package does not use the Business Processing package as shown in Figure 3-41, but instead uses the IBusinessProcessing interface provided by the Business Processing subsystem. This use of an interface allows us to focus on the service that the User Interface package uses rather than on the package providing the service. If you focus on the fact that the User Interface package uses the Business Processing package, you are unaware of the exact operations the User Interface package requires from the Business Processing package; if there is a change to the Business Processing package, you would have to expend significant effort to determine whether the change requires modifying the User Interface package. By focusing on the service that the User Interface package uses rather than the package providing the service, you are aware of the exact operations used from the package providing the service; only if there is a change to the service or to those operations do you have to expend effort to determine whether the change requires modifying the User Interface package. Rather than having to consider all the operations available inside the Business Processing package to determine whether changes to that package impact the User Interface package, you need only look at a subset of those operations: the subset defined by the IBusinessProcess interface. Similarly, notice how the Business Processing package uses the Data package in Figure 3-41, but the Business Processing subsystem uses the operations, specification elements, and IProducible interface provided by the Data subsystem in Figure 3-43.
Figure 3-43 shows the major elements that make up the project management system and the relationships between them. Using packages, subsystems, interfaces, and their relationships, you can more readily consider which elements may be developed in parallel, which elements may be purchased rather than built, and which elements may be reused. It is possible to address these issues with classes and their relationships, but because a system may have many classes, it can easily become overwhelming to work with such granularity. You could also address these issues by using packages and their dependencies, but packages don't offer services. Packages simply capture the major elements that make up a system and not the services that are being used from a package. Thus, you must focus on all the contents of a package rather than on the services used by elements that depend on the package. However, by using packages, subsystems, interfaces, and their relationships, you can more readily address the issues listed earlier, because you capture the major elements making up the system, as well as the services that are provided and required for these elements to work together to provide the functionality of the system.
Because a subsystem's operations, specification elements, and interfaces describe the services the subsystem provides, which are the only services accessible by other elements outside the subsystem, any collection of subsystems may be developed in parallel, because any interdependencies between them rely only on their services. For example, you may develop the Data subsystem and Business Processing subsystem in parallel, because any elements that use these subsystems always use the defined services.
Because a subsystem's services are fully specified, you can attempt to search for and purchase (rather than build) a subsystem that provides the same services. For example, you may not have enough funding to build the Data subsystem, but because you know the services of the subsystem, you can attempt to search and purchase a similar subsystem that offers the same services.
Because a subsystem's services are fully specified, you can reuse the subsystem whenever you require similar services. For example, whenever you require services defined by the IBusinessProcessing interface, you can reuse any subsystem that provides the interface; whenever you require services defined by the IProducible interface, the read operation, the destroy operation, the doWork operation, or the Manage Project use case, you can reuse any subsystem that provides any of these services.