因本人能力有限,无法翻译出其原汁原味来,所以就没有翻译了。望大家见谅:)
Through the Looking Glass
July 2001 <!--Date
Default Font
Bold -->
<!-- ENTER DECK HERE
Arial
Size: +1
Color: 666666 -->Subtle signs point to a marked transformation, a disruptive technology on the horizon.
<!--Author
Default Font
Italic -->by Grady Booch
<!-- IMPORT ARTICLE TEXT HERE -->Visualize, for a moment, the most recent application you've developed. Focus on an interesting code fragment, a particularly elegant script or method, or something in the main line of a primary use case realization. Imagine seeing that code, just as you created it, in your IDE or editor. Now, pop up one level of abstraction and consider the neighboring classes that provide the context for your code along with the instances of those classes that collaborate as your code runs. Line by line, walk through your code and imagine how its execution progresses, touching and manipulating the state of each instance. Finally, pop down one level of abstraction and visualize your compiler's mapping of that code to the raw instructions that ultimately direct your system's underlying hardware.
The existence of this one-to-one mapping of code (as seen in your IDE) to execution (on your target hardware) is a primary conceptual model that millions of programmers have in their heads every day as they code. It's also a primary model that generations of programmers over the past several decades have used. All in all, this von Neumann model of the world is wonderfully simple yet powerful, for it helps us build complex systems that are ultimately grounded in useful, executable artifacts.
It's also a complete illusion.
Galaxies of Abstractions
As I've said in my earlier writings, the task of the software development team is to create an illusion of simplicity. We build abstractions to help us create this illusion; these abstractions are an essential way we mitigate the intellectual complexity that lurks within our systems. Indeed, the entire history of software engineering can be traced by studying the manner in which our programming languages and methods have tried to raise the level of abstraction in our systems. That's why structured programming was effective in its time—those methods provided guidance in helping us manage the complexity of algorithmic decomposition. That's also why the object-oriented movement has been effective in its time—these methods help us organize our systems around societies of collaborating objects.
Visualize again the system architecture you considered earlier. If it's non-trivial, you'll see a universe of classes, some clumped closely together, some more distant, depending upon their degree of semantic relation. If you've used patterns to direct your design, you'll see common structures and behaviors that cut across these galaxies of abstractions.
Yet, at runtime, all of this beautiful structure evaporates. We raise our systems from the ground up, place a scaffolding of abstractions around them as they grow—and tear down that scaffolding once we're done. We might keep some scaffolding around or we could simply make it easy to reassemble if we need to extend, repair or preserve the system we've built. Ultimately, however, all of these abstractions are irrelevant to the system itself once it's in use.
Three Subtle Signs
There came a time when I'd reached "nerdvana," that state in which I was able to peer beneath the covers of the programming universe and witness the brilliant simplicity of its underlying machinery. The first time I really grasped the wonderful power of object-oriented abstractions, I thought I'd seen the ultimate model on which all kinds of complex systems could be grown. I also thought I'd encountered the most elemental structures of development—similar to the physicist's elemental model of protons, electrons and neutrons that described phenomena at the atomic level.
However, I was wrong: There's something deeper, something that's truly beyond objects.
Admittedly, this isn't a concept that's easy to explain, because I'm still so steeped in an object-oriented view of the world. However, just as a sailor can sense a changing sea, I note subtle signs that point to a marked transformation, a disruptive technology, on the horizon.
From where I stand, I see three such signs.
First, there's the patterns movement. (The seminal work in patterns is Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides [the Gang of Four], published by Addison-Wesley in 1995, which has been followed by a veritable flood of pattern books over the past several years.) At the time—and I still believe it—I declared patterns to be the one really refreshing idea since objects entered the scene. Object-oriented abstractions are great, but patterns are something subtly different, something from a truly alternative dimension of programming reality. Although classes help us organize our systems, patterns help us organize our classes, giving us guidance in extracting and exploiting common structures and behaviors. Whereas the mapping of classes to executables is only a modest conceptual leap, the mapping of patterns to classes and then to executables is a bit deeper, but well worth the effort for the complexity-management capacity that they provide. Patterns are indeed a sign of a break from the traditional von Neumann model of computation, because they name things that are somewhat orthogonal to the basic mappings of code to executables we have in our heads.
Second, there's the growing understanding of the importance of multiple views in the science and practice of software architecture. In "The 4+1 View Model of Software Architecture" (IEEE Software, Nov. 1995), Philippe Kruchten observes that there is no single, elementary view of a system sufficient to describe its architecture; rather, different stakeholders best view a complex system from different perspectives. Kruchten goes on to suggest a set of necessary and potentially sufficient views (using his more recent terminology, the design, process, implementation, deployment and use case views) that individually represent a point of entry for different sets of stakeholders and which collectively form the executable system. Perhaps Kruchten's most interesting observation is that it is reasonable—indeed, almost necessary—to grow a system by advancing each view somewhat simultaneously. As in any engineering endeavor, that process will reveal tensions among the competing interests of each stakeholder, but in turn offers a mechanism whereby progress can be made in resolving those tensions to yield a quality system.
Third, there's the emerging area of aspect-oriented programming (AOP). According to the aspect-oriented programming homepage hosted by the Xerox PARC Software Design Area (www.parc.xerox.com/csl/projects/aop/), AOP is "a new programming methodology that enables the modularization of crosscutting concerns. Experience has shown that in using standard procedural or object-oriented programming languages it can be difficult to modularize." AOP is subtly different than OOP, but it appears to complement—not replace—traditional OOP. AOP, in a manner similar to classic patterns and Kruchten's architectural views, recognizes that there are abstractions on a plane different than object-oriented abstractions, which in turn are on a plane different than our executable systems. Some of the seminal AOP papers include "Aspect Oriented Programming: A Position Paper from the Xerox PARC Aspect Oriented Program Project" (Xerox PARC, 1996), by Gregor Kiczales and others, and "Aspect Oriented Programming" (ECOOP 97 [European Conference for Object-Oriented Programming 1997]), by Gregor Kiczales, John Lamping, Anurag Medbeker, Chris Maeda, Cristina Videira Lopes, Jean-Marc Loingtier and John Irving. (See the sidebar, "What Is Aspect-Oriented Programming?" for more information.)
It's a Bird, It's a Plane, It's …
Collectively, Gregor Kiczales (formerly with Xerox PARC), John Vlissides (who works for IBM), Charles Simonyi (who works for Microsoft) and I've named this coming sea change "multifaceted software" because it represents a means of attacking development's complexity by approaching it from multiple fronts.
We aren't alone in identifying this coming change. For example, IBM Research has been working on a concept called Hyperspaces that addresses building systems through what they call multidimensional separation of concerns (see www.research.ibm.com/hyperspace/). The UML community's work to bring deeper executable semantics to the language pushes the world subtly in this direction, as well.
As software practice advances, we reach out to solve problems of increasing complexity. Most of the time, our methods fall short of our reach, but as experience grows, we can codify best practices to construct a higher, stable platform from which we can reach even higher. Structured programming represented one such platform; object-oriented technology represents yet another; and multifaceted software may be our next launchpad.
What is Aspect-Oriented Programming?
The latest methodology supports a new unit of software modularity that crosscuts traditional boundaries.
From their earliest days, programming languages have stressed various units of modularity, including subroutines, functions, procedures, modules and objects. Aspect-oriented programming (AOP) is the latest methodology to support a new unit of software modularity: aspects. Aspects are elements such as security policies and synchronization, optimization, communication or integrity rules that crosscut traditional module boundaries. At design time, a typical AOP scenario separates aspects from the classes and methods that make up application components. A code weaver (either an interpreter, compiler or pre-processor) then produces the extended classes in which aspect functionality intertwines with application components in a specific target programming language.
AspectJ from Xerox PARC is an aspect-oriented extension to the Java programming language that enables the modularization or separation of Java concerns related to error checking, design patterns, resource sharing and distribution policies. As documentation at www.aspectj.org points out, AspectJ allows Java developers to apply the "Design by Contract" style of programming popularized by the Eiffel language (www.eiffel.com) and implement pre- and postcondition testing in modular form. For example, the following code implements the bounds-checking aspect of precondition testing for point-moving operations:
aspect PointBoundsChecking {
pointcut setXs(int x):
calls(void FigureElement.setXY(x, int)) ||
calls(void Point.setX(x));
pointcut setYs(int y): ...;
before(int x): setXs(x) {
if ( x < MIN_X || x > MAX_X ) )
throw new IllegalArgumentException ("x is out of bounds.");
}
before(int y): setYs(y) {
...
}
}
Similar to AspectJ, the AspectR project adds aspect-oriented programming concepts to Ruby, an open source, object-oriented scripting language from Japan that is used like Perl to process text files and to do system management tasks. As is the case with many or most programming topics, the Wiki Wiki Web is a good place to start your AOP research: www.c2.com/cgi/wiki?AspectOrientedProgramming.
—Roger Smith