Skip to main content
  • Sign in (or register)
  • Englishspacer
  • spacer [userid]
  • spacer

By clicking Submit, you agree to the developerWorks terms of use.

  • Need an IBM ID?
  • Forgot your IBM ID?
  • Forgot your password?
  • Change your password

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • spacer

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • spacer

My developerWorks:

  • My profile
  • My home
  • My groups

My notifications:

  • {[num_notify] new notifications}([num_notify] new notification)
  • {[num_invite] network requests}([num_invite] network request)
  • Sign out
  • spacer

Select a language:

  • English
  • 中文
  • 日本語
  • Русский
  • Português (Brasil)
  • Español
  • Việt
  • spacer
  • IBM home
  • Solutions
  • Software
  • Software services
  • Support
  • Product information
  • Redbooks
  • spacer

Technical topics

  • Agile transformation
  • AIX and UNIX
  • Business analytics
  • Business process management
  • Cloud computing
  • Commerce
  • IBM i
  • Industries
  • Information management
  • Java technology
  • Linux
  • Lotus
  • Mobile development
  • Open source
  • Rational
  • Security
  • Service management
  • SOA and web services
  • Tivoli
  • Web development
  • WebSphere
  • XML
  • Technical library
  • Products A to Z
  • spacer

Evaluation software

  • Information management
  • Lotus
  • Rational
  • Tivoli
  • WebSphere
  • More IBM products
  • spacer

Community

  • My home
  • Profiles
  • Groups
  • Blogs
  • Bookmarks
  • Forums
  • Wikis
  • Files
  • Activities
  • Podcasts
  • IBM Champion program
  • spacer

Events

  • Briefings
  • Webcasts
  • Find events (briefings, webcasts, conferences...)
  • spacer
  • developerWorks
  • Java technology
  • Technical library

AOP@Work: AOP myths and realities

Beyond hype and misunderstandings

Ramnivas Laddad (ramnivas@aspectivity.com), Principal, Aspectivity
Ramnivas Laddad is an author, speaker, consultant, and trainer specializing in aspect-oriented programming and J2EE. His most recent book, AspectJ in Action: Practical aspect-oriented programming (Manning, 2003), has been called the most useful guide to AOP/AspectJ. He has been developing complex software systems using technologies such as the Java platform, J2EE, AspectJ, UML, networking, and XML for over a decade. Ramnivas is an active member of the AspectJ user community and has been involved with aspect-oriented programming from its early form. He speaks regularly at conferences such as JavaOne, JavaPolis, No Fluff Just Stuff, Software Development, EclipseCon, and O'Reilly OSCON. Ramnivas lives in San Jose, California. Visit his Web site for more information.

Summary:  What's keeping you from trying out AOP? Whether you think it's only good for low-level functions like tracing and logging, worry that it'll get in the way of unit testing, or would simply rather stick with the object-oriented alternatives, Ramnivas Laddad gives you good reason to reconsider. Follow along as this popular author and speaker digs beneath the surface of 15 myths that hinder the adoption of AOP.

View more content in this series

Date:  14 Feb 2006
Level:  Intermediate
Also available in:   Russian

Activity:  35915 views
Comments:   spacer spacer

About this series

The AOP@Work series is intended for developers who have some background in aspect-oriented programming and want to expand or deepen what they know. As with most developerWorks articles, the series is highly practical: you can expect to come away from every article with new knowledge that you can put immediately to use.

Each of the authors contributing to the series has been selected for his leadership or expertise in aspect-oriented programming. Many of the authors are contributors to the projects or tools covered in the series. Each article is subjected to a peer review to ensure the fairness and accuracy of the views expressed.

Please contact the authors individually with comments or questions about their articles. To comment on the series as a whole, you may contact series lead Nicholas Lesiecki. See Resources for more background on AOP.

Like any new and exciting technology, AOP has generated its fair share of buzz, and also its fair share of myths and misunderstandings. After following AOP coverage on the Web and listening to the questions asked at conferences, I started to see some common themes (or myths) that deserve to be cleared up.

The myths I address in this article are for the most part not malicious: many of them often stem from AOP advocates who are themselves confused about the technology. Nonetheless, these myths make it harder for developers to assess accurately whether or not to adopt AOP. Left alone, they will continue to cause incorrect perceptions and hinder the beneficial use of AOP.

Of the 15 myths I hope to resolve, two are common enough that even developers with no interest in AOP have probably heard them; a handful deal with various technologies or practices believed to eliminate the need for AOP altogether; and the remainder are systemic, having to do with the incorporation of AOP into the bigger picture of application design and development. Once I've laid these myths gracefully to rest, I'll discuss ways that you can adopt AOP in a pragmatic, risk-managed fashion, so that you can safely try it out in your own system and learn from experience rather than hearsay.

I've used AspectJ as the primary AOP implementation for examples in this article, though the arguments are equally applicable to other AOP systems such as Spring and JBoss. I'll start my discussion with the most common myth.

Myth 1: AOP is good only for tracing and logging

Reality: AOP is suitable for many other crosscutting concerns

Open any AOP book or tutorial, attend any AOP talk, or read any AOP blog and you'll surely find an example of AOP used to implement logging and tracing. Because not many of these sources show more complex examples of AOP, it's commonly assumed that AOP is good just for tracing and logging.

Why tracing?

Tracing is a poster child of AOP for a variety of reasons. First, it's a crosscutting concern whose problem is readily apparent. Second, it's particularly suitable for AOP because it is quite easy to select the required join points -- the points that need to be logged. For example, if you need to select execution of public methods, you can write a simple pointcut: execution(public * *(..)). If you want to select all exception handlers (the try-catch blocks) for SQLException, the pointcut is no more complex: handler(SQLException). If you want to do more selection such as selecting calls to all remote method invocations, the pointcut is more complex, but only slightly so: call(public * Remote+.*(..) throws RemoteException+), which selected public methods of that declare to throw RemoteException or its subclass, in Remote's subtype. These simple pointcuts make writing tracing aspects relatively effortless, and therefore are central to much introductory AOP material.

In fact, tracing and logging should be considered the "hello world" examples of AOP, which is used to implement many other crosscutting concerns. The trouble is that most crosscutting concerns aren't as easy to present at the introductory level, because of time and space restrictions. Because much of the material about AOP remains introductory, more advanced examples have yet to be widely proliferated -- but they're there!

At the system level, security, transaction management, and thread-safety concerns are commonly implemented using AOP. Many business logic problems (also known as domain-specific concerns) also exhibit crosscutting concerns upon close examination and lend themselves to modularization using aspects. On the other side, units such as classes and packages show code tangling and code scattering at a smaller scale (what I call local or micro crosscutting concerns). Aspect-oriented refactoring can help resolve these kinds of concerns by using aspects to improve the code structure. (See Resources to learn more about aspect-oriented refactoring techniques.)

Learn as you go

AOP usage follows much the same path as object-oriented programming. When you started with objects, you probably started modeling classes after domain objects -- account, customer, window, and so on. It was only after acquiring experience (and after lots of reading) that you implemented other kind of objects such as commands, actions, and observers. The same is true for AOP. Start using AOP for commonly known concerns and, as your understanding grows, you will find aspects solving problems you weren't able to even imagine before. When working on projects using AOP, you will often find that many functionalities automatically present themselves as crosscutting functionalities and lend themselves well to implementation using aspects. Many of these aspects don't fall into any definitive classification such as security or transaction management. This is not unlike object-oriented programming, where once you start programming, classes automatically show up.

Once developers understand the spectrum of problems AOP can address, some realize that AOP actually solves the same problems they've faced for years. Funny that this should lead us directly to the next most common myth about AOP.


Back to top

Myth 2: AOP doesn't solve any new problems

Reality: You're right -- it doesn't!

This is one AOP "myth" that is actually correct. AOP isn't a new computation theory that solves yet-unsolved problems. It's merely a programming technique that targets a specific problem -- modularization of crosscutting concerns.

What AOP really offers is a way to reduce the apparent complexity of a problem by reducing implementation overhead for crosscutting concerns. Developers wrestle with implementation overhead again and again in application programming; for example, when dealing with exceptions. An effective exception-handling strategy requires you to account for failure handling, chaining of exceptions, exception conversion, and so on. Further, when it comes to actually implementing your chosen strategy, you have to include the code that implements the strategy in every catch block in your system, which makes implementing the functionality much harder than it needs to be. While exception handling is an old problem, AOP handles it in a new way by reducing its complexity. Once you've chosen a strategy, you simply write an aspect implementing that strategy and you're done. All the familiar overhead of scattered implementation in the catch blocks disappears.

Two kinds of complexity

Figure 1 shows how implementation overhead increases the apparent complexity of crosscutting concerns and how AOP can help reduce the difference between both the inherent and apparent complexity of these concerns. (I'll discuss this more in a later section.)


Figure 1. Role of AOP in reducing implementation overhead
spacer

Resolving these first two very common myths is often enough to get developers thinking seriously about AOP. But for the more skeptical developer, it's necessary to go a step further. Because AOP doesn't, in fact, solve new problems (but solves old problems in a new way), it's natural to compare AOP to traditional techniques for implementing crosscutting concerns. The next three myths address techniques that are sometimes said to render AOP unnecessary. The question is, do any of these techniques provide the same advantages AOP does?


Back to top

Myth 3: Well-designed interfaces obviate AOP

Reality: Good interfaces are nice, but don't replace aspects

AOP promises to separate classes from aspects making them largely independent of each other. This separation makes it possible to swap implementations of a module without affecting other modules in the system. You can achieve a similar separation in object-oriented programming by creating abstract interfaces, which allow you to create various implementations of the same interface to address different functionality. Because both aspects and abstract interfaces make it possible to swap one implementation for another, some object-oriented developers have suggested that a well-designed interface eliminates the need for AOP. But a closer look at how each approach impacts on the application as a system tells a different story.

In AOP, the invocations to interface methods are modularized into an aspect, so it's easy to change the implementation by simply changing invocations in the aspect. For example, if you implemented logging using aspects and wanted to switch between log4j and the standard logging of the Java™ platform, you could do so by simply modifying the aspect to use the appropriate logging API. This would obviate the need for a common interface with two implementations delegating to the appropriate API.

But what about ...

The most common reaction to the above scenario is "But what about Commons Logging?" It's true that Commons Logging would allow you to swap the logging implementation without much change to other parts of the system. But consider that log4j was first released in 2000, whereas Commons Logging was released in 2003. How many of us were writing wrappers for log4j before Commons Logging was developed? Not me, for sure. Also, when you see a new API, how do you respond? By saying, "Let's create an abstract wrapper around it," or simply "Let's use it!"?

When the primary goal is to solve business problems, it simply isn't that productive, in most cases, to write a wrapper around all APIs (especially those that aren't central to the business problem at hand). Further, even if you could somehow justify the investment, it's not that easy to write a good interface. Any such interface must be abstract enough to allow the use of a wide variety of underlying implementations and concrete enough to allow uniform behavior of all implementations, from the client's perspective. If abstractness dominates the solution, you end up with the Least Common Denominator (LCD) problem, where the power of the underlying implementation isn't made available to API users. Conversely, if concreteness dominates the API, the result is a rigid API that is unable to accommodate many underlying implementations. All of this is further complicated by the fact that you don't know about implementations that you will encounter in the future. (If you did write a wrapper around log4j back in 2000, how easy was it for you to swap the underlying implementation with the standard logging API?)

If you're not yet convinced, consider this: There is no commonly available wrapper for Doug Lea's Concurrency library. This means that you either have to write a wrapper for it yourself, or (if you needed to switch over to the Java 5 java.util.concurrent classes) you would have to swap out every usage of that API with the new one. If you used aspects, on the other hand, you could simply change the aspects and be done with it. See Resources for more on this.


Back to top

Myth 4: Design patterns obviate AOP

Reality: Design patterns can introduce complexity not found in AOP

A second commonly proposed alternative to AOP is design patterns, which most developers are quite familiar with. Design patterns represent solutions to recurring problems where object-oriented programming doesn't offer a direct and simple solution. Design patterns definitely help improve modularizing crosscutting concerns to some extent, but upon closer examination, it's clear that some patterns exhibit a crosscutting nature themselves. In fact, design patterns can introduce an undesirable amount of complexity as compared to alternative approaches using AOP.

Consider the chain of responsibility (COR) pattern, which is commonly posed as an object-oriented way of modularizing crosscutting concerns. The basic idea behind the COR pattern is to add a chain of handlers around the target logic. Then you can modularize crosscutting logic into a handler. This all sounds quite useful, and it is, as shown by use of the patterns in servlets filters and Axis handlers. With COR, you can easily implement performance monitoring, session management for persistence layers, encryption/compression of streams, and certain kinds of security. But such modularity is possible only because of existing infrastructure. Without such support, you would have to implement the support yourself or face lack of modularization. For example, servlet filters have only become available since Servlet Specification 2.3. Until then, everyone implemented ad-hoc solutions.

Let's look at this sizable downside a little more closely, using the COR pattern as an example.

Did you say complexity overhead?

Optimal use of the COR pattern requires you to have one (or a very small number of) service methods, which is why it works well with servlets and Web service processors. COR wouldn't be such a good choice if you wanted to add a chain in front of an Account or Customer class without corrupting the class design itself. In that case, you would be left without any good support for your business classes.

So what would it take to implement a COR servlets filter? A lot, it turns out. First, you would need to define the filter API, shown in Listing 1:


Listing 1. Servlet Filter interface
    

public interface Filter {
    public void init(FilterConfig filterConfig);
    public void destroy();
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain);
}

Then you would need the implementation of filter chain that executes filters before executing the target method, as shown in Listing 2:


Listing 2. Core part of filter chain implementation

public class FilterChainImpl implements FilterChain {
    private int currentPos, totalFilters;
    private Filter[] filters;
    private Servlet servlet;
  
    ...

    public void doFilter(ServletRequest request, 
                         ServletResponse response)
        throws IOException, ServletException {
        if(currentPos < totalFilters) {
            Filter currentFilter = filters[currentPos++];
            currentFilter.doFilter(request, response, this);
        }
        servlet.doService(request, response);
    }
}

Next, you would need some way of configuring filters. The XML snippet to add a servlets filter, shown in Listing 3, applies performance monitoring using a filter. (Listing 4 shows the filter implementation itself.)


Listing 3. Configuring a performance monitor filter
    

<web-app>
    ...
    <filter>
        <filter-name>monitor</filter-name> 
        <filter-class>
            com.aspectivity.servlet.filter.PerformanceMonitorFilter
         </filter-class> 
    </filter> 
    <filter-mapping> 
        <filter-name>monitor</filter-name> 
        <url-pattern>/*.do</url-pattern> 
    </filter-mapping>
    ...
</web-app>

Of course, you would also need code to parse the XML, create specified filters using reflection, and put them in the filter chain. But for brevity's sake, I won't show that code.

All of the preceding code would be required to just set up infrastructure for the COR pattern in the Servlet environment. Finally, consider the filter itself. Listing 4 is a filter that simply monitors the performance of a servlet by taking timestamps before and after executing the rest of the chain:


Listing 4. Performance monitoring filter's implementation
    

public class PerformanceMonitorFilter implements Filter {
    public void doFilter(ServletRequest req, 
                       ServletResponse res, 
                       FilterChain chain) 
        throws IOException, ServletException {
        long startTime = System.nanoTime();
        chain.doFilter(req, res);
        long endTime = System.nanoTime();
  
        monitorAgent.record(((HttpServletRequest)req).getRequestURI(),
                            endTime - startTime);
    }

    // empty implementations for init() and destroy()
}

Now consider the following aspect that implements the same functionality:


Listing 5. Aspect implementation for monitoring servlet performance
    


public aspect ServletPerformanceMonitor {
    Object around(HttpRequest request) 
        : execution(* HttpServlet.do*(..)) && args(request,..){
        long startTime = System.nanoTime();
        Object retValue = proceed(request);
        long endTime = System.nanoTime();
        monitorAgent.record(request.getRequestURI(), 
                            endTime - startTime);
        return retValue;
    }
}

That's it. There is no other file in the aspect solution code (specifically, no infrastructural code is needed). While you could argue that in the COR implementation, the infrastructure code is written only once, consider that impleme

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.