UML软件工程组织

用例-昨天、今天、明天

Ivar Jacobson博士的一篇介绍用例技术的起源、发展和演进过程的文章,并在该文中对大家在实践中困惑较多的用例关系、用例数量、用例与UML等问题作了深刻的阐释,同时提出了对扩展/包含用例的改进意见,最后还对用例未来的发展趋势作出了有趣的预测。

An Introduction No other software engineering language construct with as much impact as use cases has been adopted so quickly and so widely as use cases have. I believe this is because use cases, although a simple idea, play a role in so many different aspects of software engineering. So many people have asked me how I came up with tuse case idea that I will briefly describe it here. I'll also sumwhat we have achieved so far with use cases, then suggest a fewimprovements for the future. he marize

Yesterday: In The Beginning
Use cases have now been around for more than 16 years. When I first used the term in 1986, they were the evolution of work ongoing since 1967.

Getting to Use Cases
It was 1986; I was troubled by how to model telephone calls. A modern switch at that time offered so many types of telephone calls: local calls, outgoing calls, incoming calls, and transit calls. There were many kinds of local calls; and many kinds of outgoing calls: calls to a neighbor switch, to a domestic switch, to an international switch. And, on top of this, each one of these calls could be carried out with different signaling systems.
We had discovered the problem of multiplicity and diversity many years ago. We didn't model each type of call—there were too many, and there was a lot of overlap between them—we just listed and named all of them: we called them traffic cases. Instead, we modeled the different “functions” we needed to carry out all of the calls. A function was some loosely defined piece of software. Functions had no interfaces. They had beginnings and endings, but they were not well defined. A function could interact with the outside world. The general feeling was that we didn't really know what functions were, but we could give examples of them, and some people could specify them.

However, we did know how to realize functions. I had learned a diagramming technique that described sequences of relay operations. In 1969 I translated this technique to software to describe component interactions—to what is today called sequence diagrams—the same term used when they were introduced. We described how functions were realized by using sequence diagrams (or collaboration diagrams for simpler interactions) in very much the same way that we describe use case realizations today.

Then, one day in spring of 1986, while working on traffic cases and trying to map them onto functions, I suddenly got it. A traffic case could be described in terms of functions by using an inheritance-like mechanism. I changed the terminology and made traffic cases and functions both use cases—the former became concrete or real use cases, the latter became abstract use cases.

I wrote a paper on this for OOPSLA'86; this paper is where I introduced use cases. The paper was not accepted (probably because I already had another paper for that conference, or because most people in the program committee were programming language experts). However, the paper was accepted for OOPSLA'87. This paper introduced many of the key ideas in use-case modeling.

What Was a Use Case in 1987?
According to the OOPSLA'87 paper “a use case is a special sequence of transactions, performed by a user and a system in a dialogue.” This is pretty similar to our current (informal) definition. I developed a separate model for describing an outside perspective of a system and I called it a use-case model. By outside, I meant a black-box view of the system—the internal structure of the system would be of no interest in this model. Some people have misunderstood the term “outside” and believed it to be a synonym for user interface—which it was not. Instead it represented a model of the functional requirements of the system.

At this time the use-case model also included entity (domain) objects, thus we could show how use cases could <<access>> entities. Use cases and entities were class-like (with operations) and not data. The other relation in the use case model was <<built-on>> which was described as “an extended form of inheritance relation. Multiple inheritances are common.” In fact, the built-on relation was a combination of the generalization relationship and the <<extend>> relation.

Use cases were not just specified, but also designed and tested. “You create as many processes [we would today say activities] as there are use cases. The conceptual model of the use cases is translated seamlessly into a new model showing how each use case is implemented by means of the identified blocks [a block would today be subsystem, class, or component].” This sounds pretty much like collaborations. “Each use case is tested separately to safeguard that the system meets the requirements of the user. Please, note that the use cases constitute the key aspect through the entire development activities.”

Sequence diagrams were used to show the interactions among the blocks/components. This is no surprise since sequence diagrams had shown their value in practice for almost twenty years by then.

What Was a Use Case by 1992?
In 1992 the OOSE book, Object-Oriented Software Engineering—a Use Case Driven Approach,1 was published. During 1987 and 1992 the Objectory process had been in practical use by about twenty customers for important new product development. These customers were involved in many different kinds of systems: management information systems, defense systems (pilot, counter measure, C3I), and telecom systems (POTS, mobile). What was presented at OOPSLA′87 was theory, now we had a lot of practical experience behind the idea. Over these five years use cases had matured.

Thus, use cases took much of their current shape (syntax and semantics) before 1992. At that time we had use cases, actors, use-case models, the relationships “inheritance” (now replaced by “generalization”) and <<extend>>. I didn't like what we today call the <<include>> dependency since I thought it would damage modeling by inviting functional decomposition.

To increase clarity we made it an important issue to distinguish between a use case (as a class-like thing), an instance of a use case, and a description of a use case.

The depth of the use-case model was in its use cases. Each use-case description contained the following:
? a brief description
? a flow of control
? base flows and alternative flows
? subflows (reusable at many places within the same use-case description)
? preconditions and postconditions

However, use cases were more than a requirements technique. Use cases were like the hub of a wheel2:

Figure 1. Use Cases Were Like the Hub of a Wheel

Use cases were traceable to analysis, to design, and to implementation and test. For each use case in the use-case model we created a collaboration (a view of participating classes) in analysis and design. Each use case resulted in a set of test cases. Use cases were important to design user interfaces and to structure the user manual. Use cases also moved into the space of business modeling, since they perfectly matched the definition of business processes.

We coined the term use-case driven development for our approach of software development—first identifying all use cases and specifying each one of them in requirements, analyzing and designing each one of them in analysis and design respectively, and finally testing each and every one of them in test.

We had all this before 1992!

Today: A Lot Has Happened Since Then
The adoption rate of use cases has surprised me: they were embraced almost immediately by all methodologists, and basically adopted worldwide. Other important techniques such as component-based design and object-oriented modeling were much more controversial and needed a much longer adoption time. Probably this is because use cases are basically a simple and obvious idea; they work well with objects and object thinking. Using use cases is not just a technique for managing requirements, but it binds together all the activities within a project—whether this project is a miniproject like a single iteration, or a major project resulting in a new product release.

The current definition of use cases basically goes back to 1994. To strike a balance between defining too many use cases or too few, I added a requirement that a use case must give a “measurable value” to a “particular actor.” As a rule of thumb, I suggested that a large system supporting one business process should have no more than, say, 20 use cases. I realized that giving any such number could lead people to take undesirable actions to get the “right” number. If they had less than 20 use cases, they might split some of them get up to a count of 20; or, if they had more than 20 use cases, they might combine separate use cases to get down to a count of 20. But that is the wrong approach. I have seen good use-case models for commercial systems with as few as 5 use cases and some with as many as 40 use cases. However, I have also seen use-case models with as many as 700 use cases—obviously these were unsound models. My suggested 20 use cases are concrete (real) use cases and not generalizations, or extension/inclusion fragments.

Use cases have become part of the Unified Modeling Language (UML). Because the UML is precisely defined, the meaning of use cases and associated concepts (such as use-case instance [UCI]) could also be precisely defined thanks to the UML's powerful classifier concept. What I called “class-like” in 1992 could now be formally explained by UML classifiers. We no longer needed to only rely on the old definition that “a use case is a sequence of actions…” Although this is still a compatible definition from the user's perspective, the definition based on classifiers is what methodologists, process engineers, and tool builders need for clarity. Thus the UML effort resulted in a much more precise definition of use cases, but it didn't do much to evolve them. Roughly speaking we only changed the “uses” relation to a generalization, and we added
<<include>>. (The “uses” relation in Objectory was previously called “inheritance” and was never intended to be used as <<include>> fragments.) In the past we didn't allow developers to model these fragments, but used another technique involving text objects instead; we'll discuss these later.

I am very happy with the way our Rational Unified Process (RUP) team has correctly implemented use cases and improved their practical use. No really dramatic changes have been made, but use cases have evolved to be better explained, based on the experience of thousands of customers and our own experts. In particular, a new book, Use Case Modeling3, by Kurt Bittner and Ian Spence, is now on the shelves. This is THE book on use cases. I strongly recommend everyone involved in software engineering and requirements development read it. Also Kelli Houston's RUP work on user experience design with use cases is a great improvement on our earlier work in this area, and is very much in line with the original use case concept.

Thus, now may be the time to take some steps forward to grow (clarify and extend) the idea of use cases. But first, a word of warning about formalizing use cases.

Use Caution When Formalizing Use Cases

Over the years people have criticized use cases for not having a formal enough description in the UML. Although several of my papers discuss techniques for formalizing use cases, such as using sequence diagrams to show how an actor interacts with a use case, or using activity diagrams or state charts to describe a single use case, I warned against using these techniques. After all, the use-case model is intended for communicating with customers and users. Formalizing use cases (using mathematics) has never been a problem. I had already done it in 1986. In fact, any computer science student could do it. By making use cases classifiers in UML, you have the tool to formally describe use cases to basically any depth you want.

The difficulty is, however, to use what is available in UML in the most pragmatic way. I am still reluctant to suggest that system analysts describe use cases more formally than in some textual form. Avoid trying to specify the internals of each use case with diagrams such as activity diagrams or state charts. You may describe the interactions between a use case and actors using sequence diagrams or activity diagrams with swimlanes. I think there are better ways to become more precise about requirements (the internals of a use case) than introducing more formalism in the use-case model. This is the role of analysis—but that is the subject of another paper.

Tomorrow: Potential Next Steps

Over the last decade, the way use cases were written has remained quite stable. Of course, over these years I have wanted to make improvements, however, as soon as a change was discussed, everything was questioned and things became too unsettled.

Therefore, I felt it safer to leave it as is, until people become more familiar with the use case construct. Also, we needed to allow time for use cases to be used in the field, and for their implementation to evolve and become established. In this section, I will raise a couple of issues with the current application of use cases, and indicate some proposed changes.

Some Context for the Proposals

A use-case model of a software system contains basically four kinds of use cases:

  • concrete use cases: can be instantiated (abstract ones can't)
  • generalization use cases: to support reuse of use cases
  • extension use cases: add behavior to an existing (or presumed existing) use case, without changing the original use case
  • inclusion use cases: add behavior to other use cases, and do so by changing them.

Generalizations

These use cases are abstract and generalizations of concrete use cases (through the generalization relationship) or other abstract use cases. The generalization use case (the parent use case) and its sub-use cases (children) should be of the same type to obey the principle of substitutability—you should be able to use an instance of a child whenever you expect an instance of the parent. Now, this is not quite true for use cases (or any state-driven classifier), since a child use case can require some extra interaction with the actors. However, the basic idea is the same: the child should be of the same type (classification) as the parent. For example, Make a Local Call and Make a Wake-Up Call are both generalized to the abstract use case Make a Call.

Extensions

Recall that extension use cases serve a very special purpose: they add behavior to an existing (or presumed existing) use case, and do so without changing it4. Using extensions is a technique to get easy-to-understand descriptions. First you describe the basic (mandatory) behavior, then you add extra (mandatory or optional) behavior—behavior that is not needed to understand more basic behavior. In this way you can start by describing some very simple basic behavior, and then add more and more behavior without having to change the basics. Extensions are not just a technique for describing optional behavior (optional, that is, from the customer's point of view), they are also intended for describing mandatory behavior in a structured way. Without a mechanism like extensions the base flow of a use case would become cluttered with statements that have nothing to do with the base use case, even if the statements are important for other use cases.

A potential problem in using extensions is creating deep hierarchies of extend dependencies. To avoid these we need guidelines: we usually never extend an extension (a fragment), since it would make them difficult to understand.

Another potential point of confusion is knowing when to use extensions and when to use alternative paths when describing a use case. Again, we need guidelines: we usually only use the extend relationship when the extension use case is completely separate from the extended base use case—or, more precisely, when it is a separate concrete use case in itself, or when it is only a small fragment also needed by another use case. The base use case must be complete by itself and not require the extension. Otherwise, you must use alternative paths to describe additional behavior.

Extensions can help a lot in managing software development over the entire software development lifecycle. For example, a large class of extensions could be added without requesting regression tests for the base—you would only need to test the extensions and their cooperation with the existing base. Let me qualify this. First, extensions as language constructs need to propagate through design and implementation: they need to be added to the design model, the implementation model, the executable code, and so on. (For further information look up “extends” in the OOSE book.) Second, only extensions that don't access other use cases' objects (more correctly, extensions that don't modify objects shared with other use-case realizations) would, for instance, belong to this class. When such conditions are fulfilled we could prove that some extensions wouldn't be able to damage the existing software.

I proposed the idea of extensions back in 1978 at Ericsson. Developers didn't embrace the idea until 1991. They were first published at OOPSLA 8656. But the idea had merit: Ericsson even applied for patents to support extensions. Extensions to C++ and to the operating system—in fact, also to the computer architecture—were suggested by our infrastructure team. Extensions would lower the development costs significantly. Further discussion is out of the scope of this paper, but the point is this: don't think of extensions as useful for use cases only!

I hope to address in a forthcoming aspect-oriented paper how extensions could propagate through activities other than use-case modeling—activities such as analysis, design, implementation, and test. This was as I said above actually already described in the OOSE book.

Inclusions

When use cases were born, the need for two kinds of reuse was seen. Since I based use cases on object orientation, I saw great value in subclassing, and in 1987 introduced what we called the “inheritance” relation between use cases. In 1992 we changed this to “uses” to make it less “techie” jargon and easier to adopt by analysts. In the UML it was later called “generalization.” The other reuse need was simply a mechanism for factoring common flows of events (sharing) from use-case descriptions; for cases where we currently use the <<include>> relation. This shared behavior is what I here call an inclusion.

I was very reluctant to introduce a relation like this, since I foresaw people misusing use cases by applying them as they did functional decomposition. In fact, this is one of the threats to use cases today. People misuse use cases by using them to describe functions as opposed to objects, and then blame the use-case concept for their problem. To get around this, we introduced another idea. In the Objectory tool, we supported reuse through “text objects”7, reusable objects consisting of a piece of text. These text objects could only be changed by the person responsible for the text object, not by someone else using (or reusing) the object.

Text objects could be reused in multiple places, for example in different text descriptions of use cases. Like Rose/XDE, which has a model element for each class that could be shown (differently if needed) in multiple diagrams, text objects could be shown in multiple documents. The beauty was that all the text objects were kept in one place, so they were easy to find, change and manage, and all references were automatically kept in sync. Very powerful!

I think that the solution we had was right at that time, when we feared that use cases would be viewed as just another way to do functions. This problem persists today among system analysts, although not among methodologists.

Two Classes of Extension/Inclusion Use Cases

When extension use cases originally were introduced I had basically only one kind of extension or inclusion in mind: the small reusable use-case fragment. I didn't foresee the need for being able to extend or include concrete complete use cases. This is something we learned during the first four years of practical use. Many times we8 discussed the need for two kinds of extension use cases. However, we didn't want to make use-case modeling more complex. During the UML 1.1 work we (primarily Jim, Gunnar and I) touched on this subject, but for the same reason we didn't follow through. Maybe now is the time?

There are two classes of extension/inclusion use cases:

    1. ones that are concrete (complete) use cases in themselves
    2. ones that are just fragments of a use case

Extensions/inclusions that are concrete use cases in themselves. These use cases interact with actors and can be said to provide value to an actor. As an example9, consider a “surveillance” system that reports intruders. The base (concrete use case) monitors the surveillance area, and perhaps even does some other work, such as maintaining a constant building temperature. The extending use case (also a concrete use case) reports unusual events—security breaches or fires—to the appropriate authorities (police, fire, building management). This illustrates that the base use case has some significant behavior, as does the extending use case—they are both concrete use cases, and they can both be instantiated.

Extensions/inclusions that are just fragments of a use case. This is a far larger class of use cases, but each member is usually very small. These use cases are abstract in that they cannot be instantiated separately. They are needed by some other use case—usually a concrete or a generalization use case. For example, in Figure 2, assume that the base use case is a bank transaction Conduct Transaction. Every time a transaction fails the bank wants to register this event to make it available to some other concrete use case, in this case, an administrative use case Inspect Transaction Failures. One obvious traditional solution would be to change the transaction use case and thus explicitly in its description show that a failure message has been registered. However, this would require changing the base and complicating its understanding. The change has nothing to do with the base use case Conduct Transaction; it's only there to register some information to the other use case. One such change may not be disturbing, but when you have several of them it gets to be quite messy. To avoid cluttering the base we instead use an extension use cases to add the change on top of the base use case. We would add a third use case—a very small use case fragment called Register Failures. In a similar way we may have small procedure-call like inclusion use cases that are shared between two or more concrete use cases. Assume that Validate User is such an included use case fragment (shared with some other real use case).

Figure 2. Concrete and Abstract Use Cases A part of a use-case model with two concrete use cases: Conduct Transaction and Inspect have introduced a dependency between the concrete use case Inspect

I have introduced a dependency between the concrete use case Inspect Transaction Failures and the extension use case Register Failures. Since this dependency is special and required only to attach an extension fragment to the use case that needs it, it may be a good idea to define a unique dependency stereotype (maybe <<need>>?) for it. But that is a separate issue.

The first class of use cases—concrete use cases in themselves—is fine, we don't need to do anything special about it. Concrete use cases can extend a base use case or be included in a base use case.

The second class of use cases—the use case fragments, as I will call them—will be discussed Extension and Inclusion Use Cases Have a Lot in Common ing the “execution” of s the he major difference between extension and inclusion use cases is the way the use case instance

-In the case of inclusion, the base flow itself explicitly instructs the use case instance to obey the inclusion use case.
-In the case of extension, the base flow doesn't specify the interruption, rather the extension use case specifies where in the base use case the use case instance shall make the interruption.

The extension use case references an extension point, which specifies a unique location in the base use case. In OOSE and Objectory, extension points belonged to the extending use case. In the work on UML 1.1 Jim Rumbaugh suggested that extension points should belong to the extended use case. The argument was for encapsulation—the extending use case should not see the details of the base use case, just the extension points. If you change the extended use case, only that use case would know the new location. I agree with him.

Thus extension and inclusion use cases are very similar; in fact, they could be considered the inverse of each other. Actually, when working on UML 1.1, Jim and I discussed that this shoube reflected in how the two dependencies were named. However, he was not crazy about my proposal that <<include>> should be named <<inverse extend>>, and I don't think anyone elswould have been either.

Thanks to the work on SDL in 1981, and now UML, we have come a long way in developing more precise modeling languages.

Very simply: Classical language specifications (1) start from a concrete syntactic construct (a ch ents e ince fragments are NOT use cases, they should NOT be represented by the use-case syntax. It ote, I have no good proposal for what the new notational elements should look like. To suggest Figure 3. Treat Fragments Appropriately—As Tiny Elements
notational element in UML), which is (2) mapped into an abstract syntactic construct, and whiin turn is (3) mapped onto a semantic element. The semantics specifies the meaning of the syntax. Most interesting syntactic constructs have a unique semantic correspondence. (The opposite is not necessarily true, since designed languages usually have many semantic elem[dynamic semantics] that don't have a syntactic correspondence.) Thus I think it is standard language design practice to make every unique semantic element mappable from a unique syntactic construct. Natural languages are much more complex, but since we are creating thUML language ourselves, we don't need to complicate things.
S
makes it harder for analysts to distinguish between important elements. Fragments should be treated as they deserve to be treated—as less important than real use cases.
N
something, I have chosen an icon that indicates a tiny element—a dot. However, an icon that indicates a fragment would be more intuitive. Figure 3 is an example of what I mean.
ConductTransactionInspect TransactionFailures<<extend>><<include>>Validate User
The Register Failures fragment (see Figure 2) has collapsed to a dot and its name has tion, and l he dot represents an extension fragment—the Register Failure fragment—let's call it “E.” E is he dot would be expanded (by “clicking the dot”) to a new compartment of the use case. We the example we only have one extension (Register Failures) needed by Inspect Transaction e ometimes an extension fragment is needed by several use cases (of type UC2). In these cases g to all the n igure 3 also has an inclusion fragment—the Validate User fragment. Inclusion fragments are here is an important difference between inclusion fragments and extension fragments: ? An inclusion fragment will be “executed” by the use case instance that also “executes” ? An extension fragment will be “executed” by a use case other than the use case instance disappeared. The semantics of the dot would be that while executing Conduct Transacwhen reaching the extension point, something specified by the dot will happen: an extension wilbe executed. The Inspect Transaction Failures use case will use the extension to perform its responsibilities.
T
not part of the real use case Inspect Transaction Failures (called UC2) that needs the extension. Since E is only needed by UC2 we don't need to give it a name. Instead we attach it to UC2 by attaching the dot to the use case symbol. However, it must be clear that the use case (UC2) that needs the extension E doesn't <<extend>> the other base use case Conduct Transaction (UC1) or the extension E. Thus it would be completely wrong from a language point of view to have use case UC2 <<extend>> UC1. Without the dot or something similar we wouldn't be able to properly explain the desired semantics.
T
could name the new compartment “Extensions,” and use it to describe the extensions needed bythe use case.
In
Failures. Thus in the extension compartment of Inspect Transaction Failures we would describthe Register Failures use case. Since we only have one extension, we didn't name it, but if there were multiple extensions, we might name the dots.
S
the extension fragment must be named uniquely within the use-case model. The dot representinthe extension fragment must be “free” from one particular use case, but related (via dependencies—preferably using the new stereotype <<need>> or something similar)use cases that need it. An extension fragment of this kind is a kind of classifier with an extensiocompartment.
F
not real use cases; they are reusable pieces of use-case descriptions or “text objects.” Inclusion fragments are elements separate from the use cases that include them, thus they are semanticallysimilar to extension fragments needed by several real use cases.
T
the real use case (the one that includes it).
that needs it.

With UML terms, a fragment should be a classifier with a notation that makes us think about tiny things—but now I go too deep for the purpose of this paper. We also need a syntactic shortcut (syntactic sugar) to attach a fragment to a concrete use case. We still need to use fragments in a pragmatic way.

The Day After Tomorrow: The Future of Use Cases

Over the years there have been many ideas for improving use cases. There are so many ideas and I don't know of them all, but I'll list some of them below, and introduce some others. I can't refrain from discussing the ones I am most excited about: making use cases code modules through aspect-oriented programming and making use cases run-time entities. Here are possible directions for the “future” of use cases:

  • Stereotype use cases

There are many ways to classify use cases. There are primary, secondary, etc. use cases; there are business use cases, software use cases, system use cases, etc.; business use cases are supporting, managerial or operational10, … Stereotyping is a UML mechanism for classification which would help developers in modeling of use cases.

  • Clarify relationship between patterns and use cases

Many design patterns are “template” realizations of reusable use cases. Such patterns are usually described using sequence diagrams or collaboration diagrams. A pattern is a solution to a general problem and it can be applied in different contexts. There is thus an interesting relationship between a pattern and the generic, reusable use case that specifies the problem. Clarifying this relationship would be very helpful to developers.

  • Using use cases within Human Computer Interaction (HCI)

HCI is a science. There is a way of designing a user experience by understanding the user community, its habits, and its metaphors. I was introduced to this technology by working with companies that were developing large commercial Web sites for huge user communities. Use cases would be an important concept to integrate software development and HCI approaches.

  • Cost estimations based on use cases

In 1994 Magnus Christerson lead Gustaf Karner's master's thesis11, which resulted in a paper on project estimations based on use-case points (derived from function points). To my knowledge this is still an interesting paper. With all the experience we have today about use cases and project estimations, we should be able to modernize these ideas.

  • Reusable use cases

This is a huge topic. Reuse of business software should start from understanding its use cases—both the use cases of the business, and the use cases of the software to be used. This is the depth of the Software Reuse book12 that I wrote with Martin Griss and Patrik Jonsson back in 1994-97. It is more relevant than ever today when a company's IT support is built by integrating enterprise applications, whether these are legacy systems, packaged solutions, new applications, or Web services. Further discussion can be found in my RUC 2002 talk “Closing The Gap: Business Driven Enterprise Application Integration.” (I would be happy to send this to Rational employees.)

Making Use-Case Scenarios First-Class Citizens

It would be helpful to be able to identify and enumerate use-case scenarios, and to show dependencies between these scenarios. Recall that a scenario is a use-case instance that we choose to model. This is probably more of a process issue than a language issue. There are probably many kinds of dependencies.

Iteration Dependencies

Each project iteration is driven by a number of use-case scenarios. Usually a use case is not completed within a single iteration, but is worked on over several iterations. I would like to be able to show how iterations are made up of scenarios, how a scenario grows over several iterations, and how several different scenarios over several iterations together make up a complete use case. You should be able to show, for instance, that you may have to develop less important scenarios first just to be able to develop more important instances later. As a concrete example, you may need to first develop a use-case scenario that allows a telephone system operator to make a subscriber a valid user, before that subscriber can make any telephone calls.

Test Case Dependencies

There are other reasons for dependencies between scenarios. One is for testing. Integration testing is built up test case by test case in very similar way to how iterations are built up.
We would be able to trace use-case scenarios to test cases. A good use-case scenario is a good test case. The relationship between a use-case approach and a test-first approach would become more streamlined.

Use Cases and Aspect-Oriented Programming
One of the most exciting “new” movements today is Aspect-Oriented Programming (AOP). AOP was the buzzword of the year at OOPSLA. And for very good reasons. This article cannot get into any depth about AOP. However, I can't refrain from giving some hints why AOP will make the future of use cases fantastic. The whole idea with extension use cases, that is to add behavior to an existing system without changing it, is very similar to the whole idea of aspects. Use-case realizations are implemented as aspects. Extension use cases will be realized as aspects. Extension points are semantically similar to join points.

When using the RUP, within each iteration we specify use cases, we design them, and we test them. Between design and test we must disrupt the use-case flow in order to design, code and test the components that together realize the use cases. Using AOP will simplify this: we'll go directly from use-case design to use-case programming and then to use-case test. The work on components will be supported by our programming environment (an AOPL = an OOPL + aspects). Thus AOP allows us to seamlessly implement use cases.

Neither use-case driven development, nor aspect-oriented programming are silver bullets. They represent two best practices only. However, I believe that integrating them will dramatically improve the way software will be developed.

Making Use Cases Run-Time Entities

The most exciting future of use cases is that they will also have counterparts in the run-time environment. Being able to identify executing use cases (use-case instances, in fact) in the operating system can help us with many important features as discussed in my 1985 thesis13, which had a semantic construct representing a use-case instance. A use-case instance was created by an external event, it lived during the whole interaction with the user (e.g., during the telephone call), and it tracked all the objects that participated in the use-case instance. With such a construct, we could change installed software much more incrementally—one use case instance at a time. The software system could be restarted in much smaller steps, in most cases by restarting only the use-case instance that was broken. And, we could simplify the programming of use cases. With AOP we may achieve parts of this. It seems as we will at the least achieve use-case oriented programming. ?

Final Words

Use cases have now been around for more than 15 years. We can move them a step forward by cleaning up some minor defects: by separating use cases and fragments. This can be done tomorrow.
The day after tomorrow, there are many interesting ideas to expand on use cases. Many of the ideas we have are just marginal improvements. However, two of the ideas are dramatic enhancements: making use cases code modules and making them executable run-time entities.

Until then, enjoy use cases as they are today!

Acknowledgements

I would like to thank Kurt Bittner, Gunnar Overgaard, Paul Szymkowiak for their feedback on an early version of the paper. Thanks to Catherine Southwood for editing the paper. 15 ? 2002 Rational Software 11/26/2002

 


版权所有:UML软件工程组织