Chapter 8. Editing Existing Use Cases

Analysis is a process of discovery, with many false starts and dead ends. What seemed like a good idea at the time may later become redundant or obsolete. Inevitably, some of your use cases will become out of date and fail to describe properly the system you are building. None of this is surprising, for two reasons. First, requirements specification is not a precise science. The requirements underpinning the system are themselves highly arbitrary and subject to continual change because writing use cases is frequently a revealing process. Ideas that made sense when you started writing your use cases may no longer seem reasonable as you discover more about the underlying system. Second, use cases that span multiple development cycles are likely to fall behind as the system matures and evolves in unforeseen directions. Consequently, your use cases may fail to keep up as your understanding of the system evolves.

Use cases can degrade in several ways. They might contain outdated information left over from the initial attempts at describing the system. Or, they might partition the system in a manner that no longer supports the vision or business case for the system. Concepts that once represented a useful sequence of events may now illuminate only a fragment of some isolated behavior.

Conversely, some use cases may be too big or may encompass too much functionality, describing too many actions.

You have several options available for correcting these problems. You may decide that it wasn't QuittingTime (p. 68) after all, and you need to enhance or even write more use cases. On the other hand, you may find that your use cases are reasonably complete, and you just need to spend some time reorganizing them to improve them. Obsolete use cases are the easiest to handle, as you can simply CleanHouse (p. 213) by discarding them.

In his book Refactoring, which deals with refactoring object-oriented software, Martin Fowler (1999) refers to signs that software may require refactoring as “bad smells.” One of the bad smells we think that you should always be sniffing about for in a use case is excessive length. The main success scenario of a good use case is usually between three and nine steps. A main success scenario containing more than nine steps may indicate that the use case either has multiple goals or includes lower level details. In either case, you should RedistributeTheWealth (p. 204), equitably partitioning the larger use case into smaller cohesive ones.

Another bad smell can result from use cases that fail to address a CompleteSingleGoal (p. 118) and therefore deliver only a fragment of a UserValuedTransaction (p. 95) to the primary actor. This bad smell frequently results from either CRUD-style use cases or systems in which the authors have created a use case for each user interface form (Lilly 1999).

This section describes three patterns for removing bad smells from existing use cases. RedistributeTheWealth involves separating the independent portions of an overly complex use case into simpler ones that can stand alone. MergeDroplets (p. 209) describes the opposite action of combining fragmented use cases into more complete ones. Neither of these actions is arbitrary but involves applying some rules so that the resulting use cases are both cohesive and singular in purpose. Last, CleanHouse recommends eliminating those use cases that do not provide value or help us see how the actor can achieve a goal.

You:

Children waiting in line for soup given out each night by the city mission, Dubuque, Iowa

RedistributeTheWealth

You are discovering the UserValuedTransactions (p. 95) for the system.

An excessively long use case is unwieldy and hard to use, causing users to become distracted and lose focus.

During the 60s and 70s, many corporations merged into conglomerates that operated in various unrelated lines of business. For example, Canadian Pacific Ltd. operated railways, passenger airlines, and shipping lines, and developed real estate. The multinational oil company Exxon even started a computer division. The business diversity of the conglomerate was seen as a way to protect the interests of shareholders from downturns in a specific market sector. The principle behind these conglomerates boiled down to the prudent proverb “Don't put all your eggs in one basket.”

The trouble was that the conglomerates' share prices and earnings tended to lag behind those of more narrowly focused corporations. The usual source of the problem was the difficulty corporate managers had in creating a single unifying vision for the company to embrace across all of its diversified divisions. Eventually, in the 90s, most of the conglomerates broke themselves up into separately traded corporations. In most cases, the value of the shareholder assets increased.

The use case's goal must be clear to the stakeholders. The ideal use case is clear, precise, and unambiguous because it forms an implicit contract (perhaps even a legal one) between the developers and the stakeholders. The use cases must paint a clear picture of the system, demonstrating how everyday users will normally use it in language that they can understand.

It is expensive to add new use cases. New use cases don't appear by magic; they often require the efforts of several people following a specific process. Someone must spend time sifting through requirements or talking to customers to understand a feature's basic characteristics, and then they must exhaustively identify all plausible error conditions and alternative behaviors. One or more persons need to organize this information and write the text, while others must review it. Additional use cases mean additional development work, because developers must implement the new feature. All of these efforts take time and cost money, so it makes sense to write only those use cases that provide measurable value.

Excessive detail can make use cases too hard to read and understand. Each use case should address only one goal and clearly describe how the system helps an actor reach that goal (CompleteSingleGoal [p. 118]). If a use case attempts to go beyond this scope, then the readers and even the writers can easily lose sight of the important parts of the story line in the tangents and various plot twists. Use cases that describe behavior beyond their prime objective cloud the boundaries between use cases, duplicating or even contradicting them, making the system even murkier and harder to understand.

Therefore:

Move a long, unwieldy passage or an overly complex extension to its own use case.

An effective use case will address a CompleteSingleGoal. Be especially wary of long use cases. Although size by itself may not be a problem, a long main success scenario (say, over nine steps) may be a “bad smell” indicating that the use case addresses more than one goal. When you discover that a use case has multiple goals, divide it into separate use cases, one for each goal. How you reorganize depends on the level of those goals and their relationship to other use cases.

Relocate fragments to other use cases. If the stories for these extra goals are fragments of behavior that belong in another use case, then incorporate them into that use case. MergeDroplets (p. 209) by folding these fragments into the appropriate use case, providing that you can do so without violating the other use case's CompleteSingleGoal.

Create a new use case. If the extra stories describe behavior that both stands alone and fulfills an actor's goal, then create a new use case for that behavior. This approach requires more than just moving the extra pieces to another document and calling it a use case, because the result must meet all of the criteria for a use case (CompleteSingleGoal, with a VerbPhraseName [p. 122]). It also involves making the new use case complete by extracting related information from the original use case, as well as identifying new alternative scenarios. If the resulting use case(s) are closely coupled, then this may indicate potential relationships between the use cases (PromotedAlternative [p. 190], InterruptsAsExtentions [p. 182], or CommonSubBehavior [p. 176]).

Create a new lower level use case. If there are extra story steps that describe lower level behavior, then level the use case steps (LeveledSteps [p. 153]) by creating a lower level use case with its own CompleteSingleGoal. Relocate the lower level steps to the new use case (EverUnfoldingStory [p. 102]), and reference the lower level use case from the original (this is the includes relation).

Relocate superfluous fragments to the supplementary specifications. If superfluous story fragments were included to help clarify the use case description, then save them as Adornments (p. 133).

Examples

Call Processing

Consider Use Case 8.1, which provides a simplified description of making a phone call from the viewpoint of the service provider.

While its length is acceptable, this use case violates CompleteSingleGoal (p. 118) because it describes two separate behaviors: making a phone call and billing the user. Once you detect this situation, your options include creating a new use case, creating a new sub–use case, or even including the extra information as Adornments (p. 133). In this case, Log Billing Information appears to fulfill a lower level goal and so a sub–use case is appropriate (EverUnfoldingStory [p. 102]). To RedistributeTheWealth, you should:

  1. Extract the bill logging information from the use case, and create a new sub–use case with it. See Use Case 8.2.

  2. Modify step 6 in the Process Normal Call use case to refer to this new sub–use case, as in Use Case 8.3.

Level:

A quilting party in an Alvin, Wisconsin, home

MergeDroplets

You are discovering the UserValuedTransactions (p. 95) for the system.

Use cases that describe tiny or isolated fragments of behavior don't convey enough information to help readers understand how the system delivers UserValuedTransactions.

Many of us enjoy playing with picture puzzles. There is a wonderful challenge in trying to merge hundreds, sometimes thousands, of little picture fragments into a single complete picture. Imagine sitting at the kitchen table with thousands of puzzle pieces scattered across its top. You carefully compare a fragment of sky to the picture on the box and try to position it roughly where you think it should be. Slowly, bigger pieces of the puzzle come together. Soon you will have larger fragments of sky, ground, and the castle on the hill. Some serious puzzle aficionados refuse even to look at the picture on the box; instead, they turn all the pieces over and solve the puzzle only by merging pieces without help from matching colors or images.

Use cases are not puzzles. A use case represents a CompleteSingleGoal (p. 118); a reader should not have to hunt down and mentally merge several use cases to see the complete picture.

Partial use cases are incomplete and fail to tell the whole story. An individual use case should present a “complete usage of value” to the actor. Fragments of use cases or partial use cases will cause readers to lose sight of system goals and overlook valuable features. To understand a single and complete behavior, readers are forced either to find other use cases, if they can find them, or to attempt to fill in the gaps themselves. Often, readers end up missing important features or adding unnecessary ones.

It is best to localize information whenever possible. Distributing the thread of a story throughout a set of use cases makes it very difficult for the readers to follow the narrative. Localizing information about a feature to a use case helps readers understand the primary actor's goal and the context surrounding the functional requirements.

Developers often implement systems on a per-use-case basis. If you distribute actions across multiple use cases, then you increase the likelihood that your developers will miss some features, or that multiple teams will be unknowingly working on the same features, wasting valuable development time and potentially delaying the project.

It is best to minimize the number of use cases. Every use case you must implement adds to the cost of the project, requiring you to manage, design, write, review, and test more code. Each additional feature adds an element of risk to the product, so you want to implement as few use cases as necessary when building a system, especially when time to market is an important factor.

Smaller use cases are easier to understand and use. Ideally, you want to write short, concise use cases that tell the readers everything that they need to know about a system, nothing more and nothing less. Each of your use cases should adequately describe how the system helps the actor meet one goal (CompleteSingleGoal [p. 118]), without unnecessary or technical details (TechnologyNeutral [p. 167]). Otherwise, you run the risk of overwhelming your readers.

Therefore:

Merge related tiny use cases or use case fragments into the use cases that relate to the same goal.

Merging use cases requires more effort than simply throwing several steps together and calling the results a use case, because the final product must still contain the patterns for a good use case. The best approach is to carefully edit the pieces together into a cohesive unit that describes a CompleteSingleGoal. If the resulting use cases are too large or too detailed, then refine their steps to keep ActorIntentAccomplished (p. 158), or level them to make them more understandable (LeveledSteps [p. 153]), EverUnfoldingStory [p. 102]). It is quite likely that you will also have to sift through the alternative courses, removing some and adding others.

How you reorganize partial use cases depends on their presumed goal and their relationships to other use cases.

Merge fragments to create a new use case. If several partial use cases describe behaviors that are related to the same goal, then merge them. Merging partial use cases especially makes sense when they must run in a specific order, because serial use cases are prone to repeat information. The resulting use case must still meet all of the criteria for a use case CompleteSingleGoal.

Merge fragments into existing use cases. If a use case describes behavior that belongs in another use case, then incorporate it into that use case. As with RedistributeTheWealth (p. 204), you should combine them only when you can do so without violating the resulting use case's integrity and still provide a CompleteSingleGoal.

Examples

Call Processing

Let's look at making a phone call again. It can be tempting to break down a use case into smaller, serialized use cases, with each describing a distinct functional action, as the simplified example in Use Case 8.4 shows.

This level of proceduralization is great for writing code, but not use cases. These use cases are incomplete because they describe only part of the call, and all but the first use case depend upon the completion of other use cases. Also, each of these use cases met a subgoal of our main goal, which is making a phone call. These factors indicate that we should merge these use cases.

A better way to write this use case is shown in Use Case 8.5.

This use case is much easier for the readers to follow, because it contains all of the information necessary to place, make, and conclude a phone call. The reader doesn't have to sift through several use cases to find the necessary information about this behavior; it is all there, and in order.

Also notice that in this example at least, the total number of steps required to express the behavior drops once the use cases are combined. The combined use case contains as much information as the three partial use cases, but it doesn't need to repeat the setup data or provide information to help the readers connect the separate smaller use cases.

Success Guarantee:

House adjoining a junk pile, Milwaukee, Wisconsin

CleanHouse

You are discovering the UserValuedTransactions (p. 95) for the system.

Use cases that don't contribute value to the whole are distracting and can lead the audience down the wrong path.

Our culture is one of acquisition. Closets, basements, and attics throughout North America attest to our ability to accumulate possessions, most of them long forgotten. Our garages are so full we can't park our cars in them. We spend countless hours cleaning and rearranging things, trying to find better ways of storing these belongings so that they aren't in our way, even to the point of renting expensive storage units so we can accumulate even more. Incredibly, we spend more dollars and hours boxing up these items and transporting them across the country when we move, so that we can clutter up our new garages, closets, basements, and attics. Much of this stuff we will never use again, but we keep it anyway, because “it might come in handy someday.” But do we really want polyester to come back into fashion? Ironically, people usually feel much better after they finally throw things away, and wonder why they didn't do it years earlier.

Similarly, unnecessary use cases become nothing but clutter, distracting the readers from the system's main purpose. Worse, they can waste a lot of time and energy working on something that no one wants or needs.

Cleaning up old use cases consumes time and intellectual energy. You can't modify or discard active use cases without understanding them or their value to your system. New ones are usually fresh and relatively easy to understand, but old ones often require work. Relearning takes time, and the older your use cases, the longer it will take, because you will likely need to review your entire collection before you can accurately make any changes or decide that you no longer need some of them.

Unused use cases clutter up the workspace and waste intellectual energy. Every use case you create requires some effort to maintain and adds to the cost of a project. The more use cases you have, the harder it is for the readers to keep them straight. A collection of use cases should contain only members that describe meaningful interactions between the various actors and the system. Meaningless features don't add any value to the system; rather, they only create unnecessary work for everyone using them. Unnecessary use cases can become legacy items that no one understands yet everyone is afraid to remove because they might be valuable (see the Lava Flow Pattern in Brown et al., 1998), and they remain as a fixture for the life of the system.

Removing a use case avoids a huge amount of development work and conserves intellectual energy. Every use case that you have to implement requires more time, increases your costs, and adds an element of risk to your project. You want to implement only as many use cases as necessary. Every use case that you can eliminate right from the start reduces your overhead significantly.

The consequence of leaving unnecessary use cases in your collection is that someone might try to implement them, wasting valuable development time on something you don't need, and delaying your time to market. This possibility is more likely in large development organizations, where the writers and developers are separated by organizational boundaries and don't communicate much.

Therefore:

Remove those use cases that do not add value to your system or that are no longer in your active list.

Remove these use cases from your collection as soon as you determine that they no longer contribute value (UserValuedTransactions [p. 95]). You may save any of them you feel are useful as Adornments (p. 133), but discontinue writing them immediately. A general rule for determining whether to discard a use case is “When in doubt, throw it out.” Don't worry if you throw out what later turns out to be a valuable use case. If it is valuable, then you can always bring it back into your collection later.

Weigh the implementation cost of your use cases against their perceived value, and remove those use cases whose goals are too small compared to their development cost. Some use cases cost the project more than they will ever contribute to it. Consider removing these use cases and saving some money. The chances are good that you will never implement them anyway, as you will be maintaining and enhancing more important features.

Examples

Hospital Claim

Consider the following four use cases for paying medical insurance claims for a physician's services:

  • Use Case 1: Pay Hospitalization Claim

  • Use Case 2: Pay Outpatient Claim

  • Use Case 3: Pay House Call Claim

  • Use Case 4: Pay Office Visit Claim

Each of these potential use cases describes separate and distinct situations, each having their own subtleties, expenses, and forms. But doctors rarely make house calls anymore, so Use Case 3 is impractical. It doesn't belong in the collection because it doesn't contribute any value to the system, even though it might contain interesting information that the other ones don't. It might make a good Adornment (p. 133), though, if it offered useful information.

CleanHouse addresses a real problem common to many professions beyond software development. For example, we identified several patterns while writing this book that we eventually decided not to use. Several of them were quite good; unfortunately, they became less valuable as work progressed, so we discarded them. It wasn't easy, and we had several spirited discussions about some of the patterns, but we eventually felt that the book would be much better without them.

Trade-offs and Collaborations

Writing quality use cases can be a complicated process, made even more so by the volatile nature of the underlying requirements. Goals change, and what once represented quality use cases may now be incomplete fragments of behavior or large chunks that address too many issues. We may even have written some use cases that are no longer needed. In short, and often through no fault of our own, some of our use cases fail to meet the standard of a CompleteSingleGoal (p. 118).

The patterns in this chapter are helper patterns for CompleteSingleGoal, and provide guidance for editing existing use cases to meet this standard. Each relies on CompleteSingleGoal, which states that a use case should completely address one and only one goal at its level, as the standard for determining what belongs in a specific use case. We can use this principle in two ways: determining whether something belongs in a particular use case and, if not, where it belongs. These editing patterns cover three situations:

  1. Breaking up excessively large use cases and reducing them to a manageable size (RedistributeTheWealth [p. 204])

  2. Combining incomplete use case fragments into new or existing use cases (MergeDroplets [p. 209])

  3. Eliminating unnecessary use cases (CleanHouse [p. 213])

More important, they tell us how to accomplish these actions, and what to do with the leftover pieces. Breaking up excessively large use cases involves identifying and removing information that does not pertain to the use case's goal. We don't necessarily want to get rid of this information; we usually want to redistribute it, either by moving it into a new use case or combining it into an existing one. Combining fragments into cohesive units makes it easier for readers to understand specific tasks without having to find their own path through the entire system to understand a specific function. Localizing closely related behavior in one use case also reduces the risk that some of the less informed readers might miss some detail that is buried in another, seemingly unrelated use case. Last, eliminating unnecessary use cases makes everyone's lives easier, by reducing the size and number of use cases to maintain and eliminating work for the implementers.

We may also decide that some fragments or even whole use cases no longer fit into the scheme of things, yet they contain some information we wish to preserve. We can always treat those cases as Adornments, and save this information without directly including them in our use cases.

One final note: Editing use cases can be rather involved, requiring that you understand both the system and most of the use cases in your collection before you start. This knowledge helps you identify the out-of-place pieces, as well as determine where they belong. Otherwise, you are likely to miss many of the subtleties contained in the system and make things even worse. If you don't have this experience, take some time to acquaint yourself with all of the use cases you are editing, so that you may understand them better before you begin.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.138.178