Posted on 09 Jul 2014

In any non-trivial application, functions quickly become weighed down with
supporting functionality like logging,
tracing, and metrics
gathering. These blocks of code tend to echo throughout codebases with low
variance and are referred to as cross-cutting concerns.
Aspect-Oriented Programming
(AOP) helps achieve the
separation of concerns
by pulling these blocks into modules called aspects.

Remember that AOP aims to separate concerns from business logic. Now look back
at the Phone class. How much of it is actually business logic?

Log a debug message with the method name and friend's name

If the friend picks up:

Log the call duration

Return the friend’s message

Otherwise:

Create a log message indicating the friend failed to pick
up

Throw a ‘No answer!’ exception

It turns out that nearly half our function code is devoted to concerns! Let’s
see how to separate these concerns into aspects with the
meld AOP library.

Adding Callee Metadata

To start off, let’s pull out the initial tracing statement into a piece of
advice. Advice refers to a function that acts upon another function. Here,
we create a before advice, an advice that runs before the execution of
other functions.

We use the meld.before method to apply the log advice before Phone.dial
runs. In AOP terminology, we apply the log advice at the beforejoin point of the Phone.dialpointcut. The join point is the point in
execution where the advice is applied, while the pointcut defines which
functions the advice is applied on.

Notice that join points provide relevant information about the associated
pointcut. In this aspect, we access meld.joinpoint().method and
meld.joinpoint().args[0].name to access the method name and arguments.
Join points also provide other useful meta features, as we will see in the next
section.

Tracing is an extremely common use case for AOP. It allows developers to easily
observe the passage of values through an application without modifying any
class code.

As the name implies, around advice is executed around the function being
called. That is, it contains code that is run both before and after the
function call. This special join point has a .proceed function that tells
meld to go ahead and run the function this aspect is associated with. If
joinPoint.proceed is not used, phone.dial will never be executed.

around also allows us to change the return value of the function. The return
value of joinPoint.proceed is the return value of the function call.
around’s advice can modify it freely before returning it to the caller, or
decide to return a completely different value altogether. The around advice
essentially serves as a proxy
between the caller and the callee.

around is the most powerful and robust join point in AOP due to its control
over the callee function.

Error Handling

Finally, let’s look at logging exceptions. The afterThrowing aspect is
executed after an exception is thrown.

Here, the join point passes the thrown exception to the afterThrowing advice.
afterThrowing is particularly useful for collecting metrics about where/why
an application is encountering errors. You can think of a web server
aggregating data on which URLs many visitors are encountering “404 Not Found”
errors at.

In more complex applications, this join point can also be used to implement
retry logic for code that might experience transient errors:

The afterThrowing aspect can be handy for logging and handling exceptions.

Putting It All Together

The finished code can be seen on JSFiddle or
GitHub. As you can
see, using AOP allowed us to condense our function down to 5 lines of business
logic and 3 reusable aspects.

While here we have stuck all the code in one file, developers with larger
codebases may choose to split the aspects into a separate file.

Parting Thoughts

Aspect-Oriented Programming can be useful for refactoring applications. In
addition to the types of advice discussed, AOP libraries also provide:

after advice: Run after function call, regardless of success.

afterReturning advice: Run after successful function call.

In the writing of this tutorial, I chose to use Javascript due to its
popularity and convenience, but AOP is available in many other languages.
Java, for example, has Spring AOP and
AspectJ. Both libraries, in addition to matching
the functionality of meld.js, also support greater pointcut flexibility and
reuse. There are Spring AOP snippets in my
snippets
repository on GitHub for those interested.