![]() |
Site Archive (Complete) | |||
|
ABOUT US |
CONTACT |
ADVERTISE |
SUBSCRIBE |
SOURCE CODE |
CURRENT PRINT ISSUE |
NEWSLETTERS
|
RESOURCES
|
BLOGS
|
PODCASTS
|
CAREERS
|
||||
October 01, 2003
The Case for AspectsAspect-oriented programming can finally progress beyond code-level constructs to realize true cross-cutting visibility for models. It's taken 25 years—;but now we're on the cusp of a powerful new paradigm linking aspects and use cases.Ivar Jacobson
Aspect-oriented programming can finally progress beyond code-level constructs to realize true cross-cutting visibility for models. It’s taken 25 years—but now we’re on the cusp of a powerful new paradigm linking aspects and use cases.
While interest in aspect-oriented software development (AOSD) has grown substantially since I first heard of it in former PARC scientist Gregor Kiczales’s keynote at OOPSLA ’97, it’s still primarily a topic for researchers rather than in-the-trenches developers. Most proponents tout the value of aspects for adding cross-cutting features—security, logging, persistence, debugging, tracing, distribution, performance monitoring—to a base system. These are certainly laudable properties. However, a far greater purpose for aspects lies just ahead.
Aspects could prove most powerful in application development, allowing us to
add new user features or use cases to an application for many years to come.
I believe the AOSD concept will let us gracefully extend an existing software
system iteration-by-iteration and release-by-release for the system’s
entire lifetime. This will substantially improve software quality, and will
also have a dramatic impact on the way we develop. In fact, it will have dramatic
impact on software in all traditional measures: cost, quality and time to market. Thus, it’s not just for posterity’s sake that I now present a case study I made many years ago. My conclusions then suggested that we were missing programming language support for ideas now underlying aspect orientation. In part 2 of this article, I’ll discuss how “the missing link” that has now been realized in tools from Kiczales’s PARC team (AspectJ) and Harold Oscher’s IBM team (Hyper/J) could seamlessly link to use case–driven development and provide us with a mature AOSD approach. The Case Study In 1978, while I was at Ericsson, we successfully designed a system that could be modified for years to come: It was composed entirely of customizable components interconnected through well-defined interfaces. To introduce a new feature or use case, all we usually had to do was add a new component or change an existing one. Our telecommunications switching system was considered superior to any other competitive product, and everyone seemed happy about it.However, I wasn’t satisfied, for two reasons: One, a component usually contained not only code to realize part of a dominant use case, but also small pieces of many other use cases; and two, a use case was usually realized by code allocated to several interconnected components. These two decomposition effects are now referred to as tangling and scattering. Indeed, in 1967, these well-known effects were used as ammunition against component technology. Fortunately, components won out. Still, tangling and scattering had to be dealt with. Every time a use case was modified or introduced, we had to change several components. Similarly, every time the underlying system software was upgraded (for example, making the recovery mechanism more fine-grained or adding a logging capability), we had to tweak multiple components. Articulating the Problem To get some real metrics behind my 1978 critique, I conducted a small case study of a telecom switching system consisting of hundreds of subsystems. Most of them were reusable for different customers (usually entire countries at that time), but typically each customer had his own sets of communication protocols. Therefore, we designed two customer-specific subsystems for each protocol: one for incoming calls, and one for outgoing calls. In my study, I selected a subsystem for outgoing calls and found the following:
Going through the case study, which had the small parts of 23 other use cases, I made some notes: Twelve use-case parts were noninvasive: These parts were very simple additions to the subsystem: They could be added without changing the behavior of any other part; they just needed read access to the objects shared with other parts. Eight use-case parts were extensions to but did not change the base use case: These parts required access to the execution sequence in the base use-case part (the telephone call use case). When the base use case was executed and passed a specific point in its code, these use-case parts needed to be invoked. The execution would always return to the point of invocation. Three use-case parts had major impact on the base use case: These parts needed write access to the shared objects, and they would also change the execution sequence of the base use-case part. The solution seemed obvious: If we could keep use cases separate, even while they cross several components, and maintain that separation all the way down through all lifecycle activities from requirements to test via analysis, design, implementation and testing, and, yes, also in runtime, we’d get a system that was dramatically simpler to understand, change and maintain. The Basic Idea
I was looking for a new kind of modularity to live alongside the component modularity. These new kinds of modules would cross components, and would be composed with other modules of the same kind to provide the system’s complete functional behavior. Composition would occur on all levels, both inside a component and over all components as a whole. I was asking for functional modularity, but that was before use cases—today I’d call it use-case modularity. To achieve this dream, I needed two mechanisms:
Of the two mechanisms, I prioritized the ability to separate use cases through extension mechanisms, since that would allow us to keep use cases separate down to the level of a component’s code. Integrating the separate use cases could be done by a component developer. The composition mechanism could be introduced very simply by adding a precompiler to the development environment. Furthermore, in my experience, even this very small technological change has a big payback: Many new features required only simple design extensions, and these kinds of extensions could be tested in a dramatically simpler way—we’d get more bang for the buck. Thus, my work became focused on extensions for both the use-case separation mechanism and the use-case composition mechanism, and I’d leave the much more complex work on composing use-case peers for the future. Original Extensions To explain this concept, I used the following example. The italicized text is—apart from a few modifications—a direct quotation from my 1979 paper, “Use Case Modularity.” Here, I’ve replaced the term function with use case, and reference point is now extension point. Simple explanations are bracketed, and irrelevant text has been replaced by ellipses.
From the same paper:
The micro-programmable implementation of this concept resulted in a patent application (it was not approved, for reasons I will explain in a moment). Since a large class of extensions could be safely introduced without intruding on the base, regression testing would, with proper tooling, not be needed for this class. This was expected to result in huge savings in test effort and expense. To achieve this mechanism, I introduced a few simple constructs:
In “Use Case Modularity,” I wrote: “The technology used to accomplish this is surprisingly simple in principle: Editing in runtime.” I recognized that the proposal was just the beginning of a new technique that, once adopted, would evolve on its own. A few years later, in 1986 (“Language Support for Changeable Large Real Time Systems.” Proceedings of OOPSLA ’86, Sept 1986), I generalized the notion of extensions, and introduced the neologism existion as an existing set of objects (a base). Below is a direct quotation from this presentation (with some insignificant modificationss—the term probe is replaced with the term extension point).
The Grand Vision
Unfortunately, this concept was too similar to a patching techniques—and I always had to apologize for this similarity. The aforementioned patent application was not approved because there was already a patent for patching, and my proposal would have infringed on it. In the OOSE approach (Object-Oriented Software Engineering: A Use Case Driven Approach,Addison-Wesley, 1992), we continued to support extensions in requirements and analysis, and we showed how they could be implemented in traditional object-oriented programming languages. In my book Software Reuse: Architecture, Process and Organization for Business Success (Addison-Wesley, 1997), I elaborated on variation points as a generalization of extension points. Many of these ideas have been carried over to the Reusable Asset Specification. The first serious attempt to implement extensions came with the development of a new generation of switches at Ericsson in the early ’90s. Extensions were taken into a new development environment called Delos, which supported extensions all the way down to code. Waiting for AOP Was this a groundbreaking new idea? Obviously not; it relied on patching techniques that had been known for decades. What was new, though, was the realization that “patching done right” is the most natural way to understand complex systems.However, to get where we wanted, we’d have to wait for “the missing link”s—the availability of aspect-oriented programming. It was 25 years before Gregor Kiczales, Karl Lieberherr, Harold Ossher, Bill Harrison, Peri Tarr and many more dedicated researchers gave us that missing link. Next month, I’ll describe how to complement use case–driven development with aspect-oriented programming (AOP), and how to get full lifecycle support for aspect orientation.
Ivar Jacobson is the creator of the Objectory method (which evolved into the RUP) and, with Grady Booch and James Rumbaugh, a founder of UML. While at Ericsson in Sweden, his large-scale reuse efforts culminated in a component-based approach founded on a UML-like language. His books include Object-Oriented Software Engineering: A Use Case Driven Approach (with Magnus Christerson, Patrik Jonsson and Gunnar Overgaard, Addison-Wesley, 1992), The Object Advantage: Business Process Reengineering with Object Technology (with Maria Ericcson and Agneta Jacobson, Addison-Wesley, 1995) and Software Reuse: Architecture, Process and Organization for Business Success (with Martin Griss and Patrik Jonsson, Addison-Wesley, 1997). He is best known for his invention of the use case and use case–driven development.
|
|
|||||||||||||||||||||||||||||||||||||
|
|