Aspect oriented programming is a new buzzword that has been popularized more recently through its integration with the Spring framework. The Spring guys have done a great job in bringing a difficult technology to the masses through its usual style of declarative programming. Spring AOP takes a lot of pain out of you by offering a greatly simplified programming model to have method interceptions baked in your codebase.
But making a technology look simpler has its obvious consequences of being misused. There appears to be lots of cases with programmers where they are using aspects, when good old simple Java design patterns, make a more appropriate cut. In the last couple of months, I found Spring AOP's method interception being used in many instances (including this one in an InfoQ article) when good old decorators could have solved the problem. The basic problem which the developer was trying to solve was to wrap some command with pre- and post- advices. The AOP based solution would make sense only if the same strategy needs to be repeated in multiple places and invocations of the command, which would otherwise have resulted in lots of boilerplates littering the codebase. Otherwise, a command and a bunch of decorators can provide a scalable solution to this ..
// the generic command interface
public interface ICommand {
void execute(final Object object);
}
// and a decorator interface for decorating the command
public abstract class Decorator implements ICommand {
// the command to decorate
private ICommand decorated;
public Decorator(final ICommand decorated) {
this.decorated = decorated;
}
public final void execute(Object object) {
pre();
decorated.execute(object);
post();
}
protected final ICommand getDecorated() {
return decorated;
}
// the pre-hook
protected abstract void pre();
// the post-hook
protected abstract void post();
}
// my custom command class
public class FileCommand implements ICommand {
//.. custom command
}
// my first custom decorator
public class MyDecorator_1 extends Decorator {
public MyDecorator_1(final ICommand command) {
super(command);
}
@Override
protected void post() {
//.. custom post hook
}
@Override
protected void pre() {
//.. custom pre hook
}
}
// another custom decorator
public class MyDecorator_2 extends Decorator {
public MyDecorator_2(final ICommand command) {
super(command);
}
@Override
protected void post() {
//.. custom post hook
}
@Override
protected void pre() {
//.. custom pre hook
}
}
// stack up the decorators
new MyDecorator_2(
new MyDecorator_1(
new FileCommand(...))).execute(..);
Use Aspects to address crosscutting concerns only
I use aspects as a last resort, when all options fail to address the separation of concerns that I am looking for in my code organization. Aspects help avoid the code tangle by identifying joinpoints through pointcuts and helping define advices that will be applied to the joinpoints. But I use them only when all traditional Java tools and techniques fail to localize my solution. Aspects bring in a separate machinery, the heavy lifting of bytecode instrumentation. Spring AOP is, however, pure Java, but based on dynamic proxies, which have their own limitations in method interceptions and performance penalties (however small) of creating proxies on every call. Spring AOP has less magic than pure AOP - but use the technology only if it is the right choice for the problem at hand. At least, recently, I find many instances of this wonderful technology being misused as a result of sheer over-engineering. Often, when we see nails, everything starts to look like a hammer. Keep your solution simple, ensure that it solves the immediate problem at hand and gives you adequate options for extensibility.
4 comments:
What do you mean by "when all options fail to address the separation of concerns that I am looking for in my code organization".
As I mentioned in my blog, there are many ways to address separation of concerns in a piece of software. Traditional design patterns like Decorator, Strategy etc. serve to address these issues in most of the times. Though I have personally experienced people resorting to aspects for cases which could have been solved using patterns. My theory is to go for the minimum weighted technique that solves the problem. And aspects, lie at the other end of the power spectrum. I use aspects *only* to address cross cutting concerns and only when using traditional means will lead to unnecessary code clutter.
I'm 100% with you with this one, debasih.
The Decorator pattern solves a big part of the cases when you need to apply some pre and post code.
Also, if you are working with interfaces, as it is in the case of Services, and you don't want your Service extends any special interface, you can use Java's reflection to create dynamic proxy based decorators. It sounds complex but you can do it in a 50 line "plain old Java class". You don't need to use Spring AOP or AspectJ at all and still can handle 90% of the cases.
Regards.
@Marcos:
Can't agree more. I think the most powerful part of aspects is regular expression based joinpoint matching in pointcuts. And this is where the *crosscutting* nature of aspects revel. This is the feature that the Java guys boast against Ruby metaprogramming. But often I find people misusing the power and use aspects where a simple Decorator would do.
Cheers.
Post a Comment