When people ask me "what do you think of AOP?", I tend to flinch, because the term AOP has come to be used to cover a very wide range of different uses, some of which I think are Totally Wonderful and some of which I think are Thoroughly Bad Ideas. Here's a brief survey of the range and of my reactions.

Quick Overview of AOP

The core concept of Aspect Oriented Programming is that there are common issues that apply across a range of otherwise unrelated classes. In AOP, these common issues are often referred to as "cross cutting" concerns because they cut across the normal inheritance class structure. The goal of AOP is to allow cross cutting concerns to be addressed by applying some common logic (or "aspects") to a set of classes, without having to individually modify the source code for each class.

The idea of wrapping extra functionality around target classes will be very familiar to Java EE developers. Java EE containers typically add extra functionality and semantics to target classes by intercepting incoming calls to target objects. For example, an EJB container can add transactional semantics to a target class. (Yes, J2EE has been using AOP all along!)

Java Language Principles

The Java language has been designed and evolved with certain specific underlying principles in mind.

We have put great emphasis on source code readability. As far as possible we have tried to follow the principle that "what you get is what you see". We have worked to maintain a clear and consistent base semantic model and to avoid language constructs that might undermine source code readability. People should be able to quickly read Java source code and then reliably understand what that Java source code does. That meaning should be independent of the particular compilers, tools, or runtime environments that are used.

Now, we aren't ivory tower philosophers. We want a Java language that is productive for writing and maintaining large applications. So there will always be a trade-off between principles and pragmatics. However, in looking at the success and popularity of the Java language, much of it does seem to derive from these core principles. They seem to have worked well and to be worth maintaining and protecting.

The Good: Container Based AOP

One use of AOP is based on running objects within containers. These objects can only be accessed via their container. The container can intercept incoming calls and add additional semantics. An example of this approach is the way that Java EE containers can add transactional semantics to EJB components by intercepting incoming calls.

In general this use of AOP seems fairly benign. The source code within the target objects is all behaving exactly as a developer should expect. Developers do need to be aware that they are accessing the objects indirectly and that the container may perform extra tasks. However the idea of operating through a level of indirection is a fairly normal Java concept.

Now, within this general use case, there are probably a range of good and bad uses. Uses of container intervention such as adding transactional semantics in EJB, or adding logging, or adding extra security checks seem very reasonable.

The Bad: Modifying Language Semantics

Some uses of AOP rely on using runtime mechanisms to modify semantics that are specified by the Java Language Specification (JLS). For example, side files might specify that various modifications are to be made to target classes to invoke additional code when various operations are performed. Some uses of AOP allow extra code to be invoked when fields are accessed or when methods are called.

The JLS carefully specifies the precise semantics of the Java language. For example, it precisely specifies the behavior that occurs when fields are accessed and it precisely specifies the rules by which one method may call another, including the cases when the call may proceed through other code as well as the cases when it must proceed directly from caller to callee. Developers should be able to rely on these semantics when they are reading source code.

To take an extreme example, if a developer has written a statement "a = b;" then they should be able to rely on the value of the field "b" being assigned to the field "a", with no side effects. Some AOP toolkits allow arbitrary extra code to be executed when this statement runs, so that there can be arbitrary extra side effects as part of this assignment or even so that an arbitrary different value may be assigned to "a". Yikes! Similarly, some uses of AOP permit extra code to be inserted on a method call from one method to another, even when the JLS clearly specifies that that method call will occur directly. This enables arbitrary extra code to be executed, with potentially arbitrary side effects, in situations where a Java developer should expect there will be no side effects.

This is the kind of arbitrary intervention that I think quickly races across the boundary line to insanity. (And I think most serious AOP proponents would agree.) I don't want the fundamental behavior of a chunk of source code being changed by someone magically reaching in and changing the code's meaning from the outside. That seems like a really bad idea!

The core problem with these approaches is that if someone relies on techniques like these in writing their code, then other developers will no longer be able to understand that source code, because it has been developed to rely on side effects that are both at odds with the Java language definition and which are magically applied from somewhere outside the source file. You should not need to have global knowledge of a whole environment in order to understand some local fragments of code.

Overall, using AOP to modify the meaning of the Java language seems like a really bad way to go.

The New: Java Language Annotations

In J2SE 5.0, the concept of annotations was added to the Java language. In many ways, annotations were designed to meet similar goals to AOP. The concept of annotations is that developers may apply special markers to target method, fields, or classes in order to designate that they should be processed specially by tools and/or runtime libraries.

Now, annotations are not allowed to modify the behavior defined in the Java Language Specification. Within a source file that contains annotations, at runtime all the source code must execute exactly as defined by the JLS. That was a deliberate choice - we don't want annotations to become a way of defining arbitrary magic behavior within normal Java code. However, the annotations may cause changes to the overall behavior of the program, for example by directing a container to apply special behavior when forwarding calls into a target class.

For me, one big benefit of annotations over classic AOP is that annotations are clearly visible in source code. So if you are reading an application you can clearly see which specific annotations are affecting the code. That readability advantage normally seems to outweigh the AOP advantage of being able to apply new semantics silently without modifying the affected class.

My sense is that many use cases that were initially considered for use with AOP can now be better solved by the use of annotations. That is part of what is happening with the extensive use of annotations in Java EE 5.

Conclusion

The use of container based AOP seems to provide a reasonable mechanism for supporting AOP "cross cutting concerns" within Java environments, without breaking developers' expectations of how Java source code behaves. Similarly, Java language annotations appear to provide a convenient mechanism for supporting some of the use cases originally targeted by AOP.

However, I think AOP quickly drifts from good to evil when it starts being used to mutate the meaning of source code or to otherwise modify what people can and should expect from Java source code.

So, yes, I am a fan of AOP. But of a sane, restrained AOP!

    
 - Graham