Using Packages and Subsystems

Using Packages and Subsystems

Your requirements for a system start out as simple statements from a few users—and before you know it, you have many different types of users, lots of use cases, burgeoning domain terminology, and piles of business rules. As you develop your design solution, you must contend with users’ machines, application servers, Web technology, networking, security, database performance, and a host of other issues. All this results in lots of diagrams and lots of classes to implement. To help you avoid confusion, UML provides packages and subsystems.

A package is an all-purpose way to group things such as classes, use cases, and/or diagrams together—and it’s represented as a tabbed folder. Packages help you keep your development organized. Packages own what’s inside them, and the internal contents of your packages are either public (visible outside the package), private (hidden inside the package), or protected (visible to package extensions, hidden from external packages).

A package can import the contents of another package and then use the imported package contents as if they were inside. You refer to an element like a class that belongs to another package with the PackageName::ElementName notation. For example, Product::AirFilter refers to the AirFilter class owned by the Product package.

 Tip   You use packages to organize your requirements at analysis time. You use subsystems to organize your solution at design time. You can treat subsystems just like packages. In UML 2, subsystems and packages are not exactly the same thing, but they are close enough. (Subsystems are shown as a rectangle with a small fork icon in the upper right-hand corner.)

We use packages and subsystems during analysis and design as follows:

  1. Develop analysis packages.

    During analysis, you can start grouping classes that must work together into the same package. You can also group your use cases by creating a package for each actor and placing the use cases initiated by that actor in the package.

  2. Reorganize packages for system design.

    When you start designing your system, move classes and use cases around to group things together for your developers. Developers appreciate packages organized by important use cases, hardware, development schedule, or department ownership of the information. We’ll give you more details on reorganizing packages later in the chapter.

  3. Convert packages to subsystems.

    Change the packages into subsystems. The subsystems now hold and own, the contents that the packages did. The value of this step comes later when you design the details of each subsystem.

    Not all analysis-time packages turn into subsystems. You might keep a package that holds common datatype definitions during design time. Subsystems in your system import the contents of the datatype package.

  4. Consider dependencies.

    Look at each subsystem and examine how it may (or may not) depend on the contents of other subsystems.

  5. Reorganize subsystems.

    Rearrange the contents of your subsystems to either increase dependencies (for performance) or decrease dependencies (for modularity) among your subsystems. At this stage, you use architectural design patterns such as faзade or three-tier to reduce subsystem dependencies and increase the flexibility of your system’s design. (You can find more about faзade and three-tier patterns in the section “Using other architectural patterns,” later in this chapter.) Doing so can often lead to a change in how you arrange your subsystems. If you reduce subsystem dependencies, you can have teams of designers work independently on each subsystem.

  6. Design subsystem details.

    After you’re satisfied with the overall organization of your subsystems, then you begin designing their details. UML enables you to show the specification (requirements) and the realization (implementation details) for each subsystem.

 Remember   If you organize your subsystems well, then teams of developers can design each subsystem without worrying about how the other subsystems are designed.

Creating analysis packages

The systems you analyze are probably large and complex with many different types of users, too many classes to remember, and lots of different behavioral interactions among the classes. To keep it all straight, we use packages during analysis. Here are some of the packages we find useful during system and software analysis:

  • Domain groups: Group your domain classes (classes that reflect the terminology of the user, like hotel, room, or reservation) into a package. If you have lots of classes, then consider creating subpackages to further organize these domain classes. Look for a group of classes closely associated with each other and loosely associated with other classes in the domain. You can also look for classes that participate in any of the following:

    • Classification scheme: You organize these classes into an inheritance hierarchy. Sometimes this makes for a good grouping.

    • Aggregation: If you have an aggregate class that has a lot of parts, put the aggregate class and its parts into their own package.

    • Persistent class group: If some (but not all) of your domain classes must persist (live beyond the life of the running application), place them in their own package.

  • Actors and use cases: Each actor interacting with your system uses that system for its own purposes, which is a different from the purposes of other actors. Create a package for each actor and place the use cases for that actor in their respective package. If an actor has a lot of use cases (more than 5–9) consider creating subpackages to group the use cases more specifically for that actor.

  • Application class groups: As you consider the classes required by your application, place them either in an appropriate use-case package or create a separate package to hold them. Such application classes are the control, view, and boundary classes that an application needs so it can make a use case work properly for an actor.

  • Common datatypes: Often classes can represent enumerations (such as eye color), data classification (including units of measurement such as miles for distance and pounds for weight), and abstract datatypes (such as address, currency, or date). Place any such common datatype in a package so you have one definition of it that everyone can reuse.

 Tip   You can continue to use packages during the design phase of your project as a general-purpose way of grouping elements from your UML diagrams together. However, we like to use subsystems during design because they allow you to show how specific requirements are realized by a group of cooperating classes.

Figure shows some of the packages for an air-filter product business. The order clerk and the clerk’s use cases are owned by the Order Handling package. The Account Billing package contains the accountant actor and use cases directly accessed by the accountant. A separate Analysis Datatype package holds several classes stereotyped as enumerations and a couple of abstract datatypes.

Figure: Analysis packages for actors, use cases, and datatypes.

The domain packages for the air-filter business example are shown in Figure. To keep the diagrams simple, we don’t show all classes and associations. You can see some of the classes owned by the Customer Accounting package, but we don’t show the contents of the Supplier Accounting, Airfilter Product, and AirEvents packages. Call it an exercise of a handy UML feature: showing or hiding the contents of a package as needed.

Figure: Analysis-time packages for problem domain.

Creating subsystems

If your analysis results in a lot of classes and required behavior to make the system or software conform to what your users need, then you need to organize your design using multiple subsystems. During design, you can create subsystems according to the following criteria:

  • Use cases: You can create subsystems that focus on a group of similar use cases. The analysis-time packages that you based on your use cases are good starting points when you’re creating these subsystems. As when creating the analysis-time packages, you should look for use cases that have the same actor. The air-filter business example has two such subsystems: Order Handling and Billing.

    When creating subsystem, keep use cases that depend on other “included” use cases in mind. You should ask yourself: In which subsystem should I place the “included” use case? There are a couple ways to answer this question:

    • You can place an included use case in the subsystem where it’s most often used—and let other subsystems import it if they need it. For the air-filter example, we chose to put the Check Credit Card use case in the Billing subsystem instead of the Order Handling subsystem because the accountant uses it more frequently than the order clerk does. The Order Handling subsystem will import the Billing subsystem. During design, you’re allowed to move things around if it meets your design priorities.

    • Alternatively, you can place the included use case in its own subsystem. Other subsystems that need the behavior of the included use case must import the behavior. We favor this approach if several other use cases in our system must access the included use case. If you chose this option for the air-filter example, you would create a subsystem, call it Credit Check, and place the Check Credit Card use case with in it. The Order Handling and Billing subsystems would depend on the Credit Check subsystem.

  • Hardware and software: Your information system has software that runs on hardware. You can use this as a basis for creating subsystems. Consider the following examples:

    • Hardware: Create subsystems around the different kinds of hardware in your system. The Order Handling subsystem, for example, can be broken down into two more subsystems: Web Orders for handling orders placed over the Internet and Clerk Orders placed on standard-issue office equipment of the order clerks.

    • Software: You have three kinds of software in your system: new software you develop, old legacy software that you have to use for a while yet, and commercially purchased software (such as application programs, transaction managers, database-management systems, and office software suites). Create subsystems to contain each of these different types of software. (The air-filter business would need a subsystem for the commercially purchased database-management system.)

  • Schedule: You don’t always get the chance to build and deliver the required software for your system all at once. You have a schedule you must follow, rolling out specific pieces of the software over time. You can create subsystems that group related use cases (and the classes that implement those use cases) for each delivery deadline in the schedule. If you built subsystems according to the schedule in the air-filter example, you’d need a subsystem containing Setup New Customer, Invoice Customer, and Check Credit Card use cases for the first scheduled rollout. The second rollout would have a subsystem containing the Generate Product Order and the Review Accounts use cases.

  • Ownership: If you have developers from different departments who must take ownership for a particular piece of the system, consider creating subsystems based on that ownership. If we have developers with accounting expertise, then we create a subsystem and place all accounting-oriented classes, use cases, and components in it. Similarly, the database department is responsible for (you guessed it) the database subsystem.

  • Deployment: Today your applications are spread across the user’s computer, Web servers, application servers, and database servers. You can create subsystems based on where you deploy the software. The air-filter business needs subsystems for the software that gets deployed on each of these different machines.

Figure shows a group of subsystems based on the analysis-time packages for the air-filter business example. The two analysis-time use-case packages lead to the Order Handling and Billing subsystems. (The Billing subsystem contains the Check Credit Card use instead of Order Handling.)

Figure: Example of design time subsystems.

At analysis time, all the different domain packages lead to a subsystem that holds all the common objects. The Common Objects subsystem contains several sub-subsystems—Customer, Supplier, and Product. The Persistent Store subsystem provides an interface to a back-end relational database-management system. The Security subsystem handles all login and user authorization tasks. The Accounting System Interface provides access to a legacy accounting system.

 Remember   The Analysis Datatypes package is now called the Domain-Datatypes package for the system design. Not all analysis packages convert to subsystems.

 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows