With the growing interest in aspect-oriented programming (AOP), more developers are evaluating what the technology can do for them, asking questions and sharing concerns. And, in our modern world of blogs, those initial concerns generate wide discussion. In that context, it's worth presenting the basic case for AOP once more.
First, what is AOP and what is it for? AOP is, first and foremost, a concept for structuring software designs and code. AOP adds the concept of aspect to the more familiar concepts of procedures and objects. Aspects are useful for designing and implementing crosscutting concerns, which are elements of systems that inherently involve more than one object (or procedure).
To understand crosscutting concerns and aspects, consider that when you think about an algorithm, like compute customer discount, you naturally reach for the concept of procedure. And when you think about a concept like shopping cart or customer, you naturally reach for the concept of object.
But what about when you think about a concept like observer pattern or synchronization strategy? These don't fit into procedures or objects. You can't easily imagine writing a single class that implements the observer pattern among a handful of other classes in your system, because the observer pattern is a crosscutting concern. Aspects were invented to cleanly capture crosscutting concerns. We can naturally design and code aspects for observer patterns, synchronization strategies, optimizations, business rules, persistence mechanisms and countless other crosscutting concerns.
Mangling the Misconceptions
At this point, it's worth debunking several myths.
Aspects are always infrastructure or auxiliary parts of an application. Wrong! There are great infrastructure aspects, such as persistence. But some aspects are central to an application's business logic, like discounting rules, order processing rules and the like. As a rule of thumb, aspects are modules, just like procedures and objects. Some aspects are auxiliary, just as some objects are auxiliary, and some aspects are central, just as some objects are central.
If you use OOP properly, you won't need to use AOP. Nope! Everyone who developed AOP understood OOP well. AOP was invented because some designs can't be written in a simple way using objects (or procedures), they involve an inherent crosscutting structure. Those are the cases that need AOP. Using OOP well, including patterns, might make your design and code fairly good in these cases, but using AOP will make them better. Consider a system of a couple dozen classes, with four or five crosscutting patterns floating around; maybe even two occurrences of the same pattern. Even if the code is well written, it will be difficult to understand because code for any crosscutting patterns will be mixed up with the classes. Code written with AOP, however, will be nicely separated, and your code and design will be easier to understand and change.
Just as you probably don't want to make a class for something that a simple procedure (a.k.a. static method) can hold, such as computing the distance between two points, you shouldn't use an aspect for something that a class can hold. You should always use the simplest tool that works, but some jobs really require AOP to create a simple, clear and modular design.
AOP should be used only when making changes to an existing application, not in the initial design and implementation. No way. Like classes, aspects can be used to extend an existing system. Most AOP adoption happens this way, of course. But you get the greatest value when you think about aspects in your design as well as your code. You can do that when changing an existing design and implementation or when developing a new design and implementation.
AOP code is difficult to understand. Au contraire! In fact, given simple tool support, well-written AOP code is easier to understand than the equivalent plain OO program.This misconception arises from the concern that while AOP makes the aspects themselves more clear, it may make the interaction between the aspects and the objects (or procedures) they crosscut less so. If you write an aspect that synchronizes the behavior of a set of objects, how do you know how the synchronization interacts with the specific methods in the objects?
First, consider the non-AOP version of the same functionality. In this code, a number of places invoke various types of synchronization functionality. For example, "Be sure to grab this lock when entering this region." In the non-AOP code, it's easy to see that each particular method does that, but it can be hard to see the common structure or pattern. You won't forget that one method grabs a lock, but you'll have a hard time understanding the overall strategy and figuring out whether there's a synchronization bug. In AOP code, the raw source code doesn't show which methods the synchronization aspect advises. But simple existing IDE support does provide this information, in the form of auto-generated margin notes. So the IDE support gives you everything you had in the non-AOP code, in terms of comprehensibility.
But in the AOP code, the overall structure is evident. You can see, in a single place, the rules that designate where locking and unlocking happens. And that's a better deal in terms of understanding what your code is doing, and finding and solving the toughest problems.
AOP in Practice
Like procedures and objects, there are many ways to support an aspect-oriented style. You can think aspects in your design and write "aspect-inspired" code, even if you use an ordinary OO (or procedural) language. To do this, you use some coding style conventions, so that your crosscutting concerns are implemented consistently, and it's easy to recover the aspect from the code. This shouldn't be surprising. If you wanted to, you could adopt an object-oriented style in plain C.
But the best way to work with aspects is to use an AOP language. With OOP, Java is more restrictive than if you do your own hand-rolled OOP in C, and you want that more restrictive version because it reflects best practices and makes your code easier to understand. The same is true of AOP. Leading AOP languages, like AspectJ and AspectWerkz, are more restrictive than hand-rolled solutions and are more suitable for commercial use. This brings up two more misconceptions.
AOP is a preprocessor technique. (Or AOP is a compiler technique, or a load-time technique.) Yes and no. Because AOP is a concept that can be supported by a language, it's amenable to a wide range of implementation techniques. The first implementations were preprocessors, but that doesn't mean AOP is a preprocessor technique—just as the fact that the first C++ implementation was preprocessor doesn't mean that OOP is a preprocessor technique. The same is true for compile- and load-time implementations. As AOP implementations mature, we're seeing a split into compile time and runtime, with type checking and related work occurring at compile time, and weaving taking place later. We're already seeing runtime weaving work by AspectWerkz, IBM and TU Darmstadt, and weaving should migrate into the core virtual machine.
AOP is just another framework/API/library. Wrong again! AOP can be supported by frameworks, APIs and libraries, but it's about something more fundamental than a new set of handy routines. AOP is a new concept for structuring software designs and code. As an indication of this fundamental nature, almost 20 universities now teach AOP as all or part of graduate and undergraduate software engineering courses.
Of course, for all of you experienced AOP developers, none of this is new. But it may help you clear up any AOP misconceptions you encounter among your skeptical-but-interested colleagues.
Vancouver-based Gregor Kiczales led the Xerox PARC teams that developed aspect-oriented programming and AspectJ.