You’ll often run into déjà vu as you document your use cases—especially when several of them show an identical sequence of events exchanged between an actor and the system. This is more than coincidence; multiple use cases often have common subsequences. Usually (for example), some common setups or prerequisites must be established before work even begins—and common subgoals have to be reached on the way to accomplishing the actor’s goals.
Recognizing this commonality is good—because if you don’t recognize it, you can end up doing your use-case work twice. Doing the same thing over again is bad enough, but the consequences to your project can be worse. If you document your use cases twice, you’ll likely document them differently—which leads to designing, implementing, and testing them differently. Such systems are also costly because such a lack of reuse adds complexity—and your users may easily get lost in a system that shows no cohesion. They’ll have to learn and remember different techniques to accomplish the same goals in different contexts.
To save everyone some hassle, it’s worth looking for opportunities to reuse common pieces of use-case interactions between an actor and the system.
In the Hotel Reservation system diagrammed in Figure 10-1, the actor Potential Guest may trigger the use case Make Room Reservation—and another actor, Event Organizer, may trigger the use case Make Facility Reservation. Both use cases involve an additional actor, the Credit Card Authorization System, to guarantee a reservation.
Figure 10-1: Potential commonality in use cases.
After a little thought, you may notice a set of interactions that Make Room Reservation and Make Facility Reservation have in common: the process of verifying the credit card. This common set of interactions begins with the actor requesting to pay by credit card, and the system responding with prompts for credit-card information (such as type, number, date, and name). After the actor fills in the fields, the system validates their values, and passes the information to the Credit Card Authorization system, along with an estimate of cost for the room or event. Here the information is verified; if it’s acceptable, the system puts a hold on the credit card for the estimated cost. There are several alternate paths to this result—for example, validation errors, insufficient credit, card reported stolen, and so on. (You can see the Make Room Reservation use case, which includes these flows, documented in Chapter 9.)
You can add such sets of common interactions to a new use case of their own—which you can then include wherever you need it.
In Figure 10-2, for example, you can see that we pulled out the common interactions of two use cases and placed them in a new use case called Guarantee Reservation. We show the relationship by drawing a dashed arrow between the base use cases (the ones doing the including because it needs the common behavior) and the common (included) behavior, labeling the arrow with the stereotype «include». The resulting include relationship points from the base use case to the included use case, indicating that the included use case is a necessary part of the base. This included use case is a real use case; you document it in the same manner as a base use case.
Tip Though it uses a different notation, the «include» relationship is similar to the aggregation relationship discussed in Chapter 5.
Figure 10-2: An included use case.
Tip An included use case is often handy (and needed) when several use cases share a secondary actor, such as Credit Card Authorization System. Often these secondary actors are dealt with in common ways (share common exchanges of events) from a number of different use cases. If the interactions with the actor are the same and significant, it’s worth your time to make a new use case for those interactions so you can simply «include» them.
You may have one difficulty when you attempt to document the included use case: How do you identify the primary actor? After all, three different actors are involved with the Guarantee Reservation use case—and at least two of them are potential primary actors. In fact, you should consider both Potential Guest and Event Organizer as primary actors (yes, there can be more than one). Any primary actor for any base use case is also a primary actor for the included use case. You must document the included use case in a way that allows any primary actor to interact with the system being built. You can see one way of doing this in the following example, which is the beginning of the documentation for the Guarantee Reservation use case.
Warning There’s also a bit of controversy about how to document these included use cases. If you look at the following, you can see that we have a spot in the header to list the base use cases (Make Room Reservation and Make Facility Reservation). Normally, object-oriented principles guide us to hide the identity of the callers from the called. This bit of information hiding allows us to change the identity and number of callers (that is, the base use cases) without requiring us to rework the called (that is, the included use cases). When you implement your use cases, however, it’s often worthwhile to ease up on the information hiding when you’re doing the documentation. As you may expect, too much information hiding makes it hard to communicate well. (For more about object-oriented principles of information hiding, see Chapter 2.)
Use-case name: Guarantee Reservation
Description: This use case allows the actor, either Potential Guest or Event Organizer, to guarantee a reservation using a credit card.
Base use cases: Make Room Reservation, Make Facility Reservation
Main course of events: Successful credit card guarantee.
Precondition: Actor is ready to guarantee the room or facility reservation with a credit card. The system already knows the expected cost of the reservation.
Successful post condition: Actor has guaranteed the reservation.
Potential Guest or | System | Credit Card Event Organizer Authorization System |
---|---|---|
1. This use case starts when the actor is ready to guarantee the reservation. | 2. Prompts for billing information. | |
3. Supplies name, billing address, credit card number, and expiration date. | 4. Validates inputs data validation rules X through Y. 5. Sends transaction to Credit Card Authorization system. | 6. Reports transaction is accepted. |
7. This use case ends when the guarantee is accepted by the system. |
You may also generalize the potential actors and refer to them in their generalized form. In Figure 10-3, we’ve generalized Potential Guest and Event Organizer into a new actor named Reserver. In this situation, the Potential Guest actor and the Event Organizer actor—for as long as they’re participating in the Guarantee Reservation use case—share common goals and purposes. Thus, when you document the included use case, you can refer to Reserver as the actor. This is an especially good technique when you have many base use cases, each with its own primary actor. If you don’t have to explicitly refer to each individual actor, you improve readability, save some documentation costs, and produce more change-tolerant documentation.
Figure 10-3: Generalizing actors.
Warning These advantages come with a caveat: When you produce the use-case diagram, don’t connect the included use case directly to the generalized actor. That way lies confusion; primary actors of an included use case are implicitly the actors of the base use case(s). Adding a connection to the generalized actor just adds another actor to the use case—one actor too many. This common diagramming error indicates that another actor instance is required to execute the use case—when it isn’t.
Use-case diagrams are, by and large, graphically simple. With only a few actors and a few ovals per actor, you can convey lots of information about your system (such as its users and services). Adding «include» relationships can complicate the diagram slightly, but you gain clarity by highlighting areas of commonality and regularity. It’s comforting to understand a system deeply enough to identify areas of uniformity—and practical, because it enables reuse and predictability.