The term package has been overloaded with many meanings in software. For our purposes, we focus on one particular kind of package, often called a component. A component is an independently deployable binary unit. In .NET, components are often called assemblies and are carried within DLLs. As vitally important elements of large software systems, components allow such systems to be decomposed into smaller binary deliverables. If the dependencies between the components are well managed, it is possible to fix bugs and add features by redeploying only those components that have changed. More important, the design of large systems depends critically on good component design, so that individual teams can focus on isolated components instead of worrying about the whole system. In UML, packages can be used as containers for groups of classes. These packages can represent subsystems, libraries, or components. By grouping classes into packages, we can reason about the design at a higher level of abstraction. If those packages are components, we can use them to manage the development and distribution of the software. Our goal in this chapter is to learn how to partition the classes in an application according to some criteria and then allocate the classes in those partitions to independently deployable components. But classes often have dependencies on other classes, and these dependencies often cross component boundaries. Thus, the components will have dependency relationships with each other. The relationships between components express the high-level organization of the application and need to be managed. This begs a large number of questions.
This chapter outlines six principles for managing the contents and relationships between components. The first three, principles of package cohesion, help us allocate classes to packages. The last three principles govern package coupling and help us determine how packages should be interrelated. The last two principles also describe a set of dependency management metrics that allow developers to measure and characterize the dependency structure of their designs. |