Saturday 22 February 2014

Aspect Oriented Programming

To clarify, I am a big fan of Aspect Oriented Programming (AOP). Interestingly, AOP was invented by folks in Xerox PARC, who I am working with now. As this programming paradigm is success and widely adopted in the industry, all the programmers should have a good understanding of it.

What is Aspect Oriented Programming?

If you look at Wikipedia, they say

"aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns"

I am not very sure if you understand what they are saying. For me, after 6 or 7 years using AOP, I still have a hard time figuring out what this definition is trying to describe. Technically, it is perfectly accurate but it may not give you a clue of what is AOP and why should you use AOP. Let me try to explain it in my own way.

When you do your coding, there are always business logic and some boilerplate code. Boilerplate mixing with business logic is what you do not like because it make the code difficult to read and developers less focus on business logic. AOP attempt to solve this issue by an innovative way of splitting boilerplate code out of business logic.

There are two characteristics that boilerplate code need to satisfy if it is to be removed from business logic:
  • It is generic enough to be commonly executed for various objects.
  • It must happens before and/or after business logic .   
When the first characteristic is satisfied, you can remove the boilerplate code and put it to some other places without any harm to the functionality. When the second characteristic is satisfied, we can define a point-cut or cross point on any objects that suppose to run this boilerplate code. Then congratulation, the rest of work is being done by the framework. It will help you to automatically execute the boilerplate code before/after your business logic. 

Why AOP is cool?

AOP is cool because is make your project cleaner in many ways
  • You do not mix boilerplate code with business logic. This make your code easier to read.
  • You save your self from typing the same code again and again.
  • The code base is smaller and less repetitive. 
  • Your code is more manageable. You have the option of adding a behaviour to all class/methods in your project in one shot.
To let you feel the power of AOP, let imagine what will happen if you have this magic in real life. Let say in one command, you can make every citizen of Singapore donate 10% of income for charitable work. This sound much faster and less hassle than go to ask every individual to do this for you. This example show that AOP work best when you have lots of objects in your system that sharing the same feature. 

Fortunately, there are lots of common features like that in real applications. For example, here is some stuffs that you will often need to implements:
  • Log the execution time of long running method.
  • Check the permission before executing method.
  • Initiate transaction before method and close transaction after method completed.
How to implement AOP?

If you want to share boilerplate code, you can implement it in the old-fashion way. For example,

import java.util.logging.Logger;

public abstract class LoggableWork {
 
 public void doSomething(){
  long startTime = System.currentTimeMillis();
  reallyDoWork();
  long endTime = System.currentTimeMillis();
  Logger.getLogger("executableTime").info("Execution time is " + (endTime-startTime) + " ms");
 }

 protected abstract void reallyDoWork(); 
}

Then any class can extend the abstract class above and have their execution time be logged. However, the world has long abandoned this approach because it is not so clean and extensible. If you finally figure out that you need transaction and security check, you may need to create TransactionWork and SecuredWork. However, Java do not allow one class to extend from more than one parent and you are stuck with your awkward design. For your information, there are two more problems with the approach mention above. It force developer to think of what boilerplate code they need to have before writing business logic. It is not natural and sometimes not predictable. Moreover, inheritance is not a favourable way of adding boilerplate code. Logging execution time is not part of business logic and you should not abuse your business logic for whatever cool stuff that you want to add on your project. 

So, what is the right way of having AOP? Focus on your business logic and create your class/method without worrying of logging, transaction, security or anything else. Now, let add the logging for execution time for every methods in the system:

@Aspect
public class LogAspect {

  @Pointcut("execution(public * *(..))")
  public Object traceAdvice ( ProceedingJintPoint jP, Trace trace ) {

    Object result;
    long startTime = System.currentTimeMillis();

    try { 
      result = jp.procced();
    } finally { 
      long endTime = System.currentTimeMillis();
      Logger.getLogger("executableTime").info("Execution time is " + (endTime-startTime) + " ms");
    }

    return result;
  }
}

What you just create is call interceptor. The annotation @Pointcut define the place that you want your boilerplate code to be insert to. This line tell the framework to let the method executed as usual:

result = jp.procced();

Then, you mark the time before and after the real method is executed and log result. Similarly, we can create Interceptor for transaction and security check as well. The terms you see above (PointCut, Aspect) is taken from AspectJ. One aspect represent one behaviour you want to add to your project. That why the approach of writing business logic first and adding aspect later is called Aspect Oriented Programming.

There are thousands of ways to create a point cut and above example is one of them. You can create point cut base on package, annotation, class name, method name, parameter type and combination of them. Here is a good source to study AspectJ language:

https://eclipse.org/aspectj/doc/next/progguide/language.html

Want to know more about underlying implementation of AOP?

If you just want to use AOP, the above parts are sufficient, but if you really want to understand AOP, then better go through this part. AOP is implemented using Reflection. At the beginning day of Java, reflection is not recommended to be used in real-time execution because of performance issue. However, as the performance of JVM improve, reflection is getting popular and become the base technology to build many frameworks. When you use any framework that based on reflection (almost all frameworks in the market), the Java object is no longer WYSIWYG (what you see is what you get). 

The object created in JVM still respect  the contract of class, interface that it belong to but it have more hidden features than what you see. 


In our case, the objects, which execute method doSomething() is a proxy of the contract class. The framework construct the bean and create the proxy to wrap around it. Therefore, any time you call the bean to doSomething(), the proxy code doBefore() and doAfter() are executed as well. You even have the choice to bypass the invoking of method doSomething() on the inner bean inside (for example if they fail permission check). 

It is easy to see this only work if you let the framework create the bean for you rather than create the bean yourself. I have encountered some developers asking me why this code does not log:

Bean bean = new Bean();
bean.doSomething();

It is so obvious that the developer create the bean him self rather than the framework. In this case, the bean is just an ordinary Java object and not proxy. Hence, it is out of framework control and no aspect can be applied on this bean. 







2 comments: