I previously posted that I had attended a workshop hosted by Microsoft Research on the topic of Aspect Oriented Programming.  The core purpose of AOP I’m a firm believer of: to modularize systems more effectively.  But I’m still not sold on the AOP implementation of this directive.  

 

But, I do fine AOP intriguing and have developed an implementation that uses dynamic runtime weaving (more about this below).  It works pretty well, and doesn’t degrade the application performance too bad.

 

Anyway, for those who want to learn some more about AOP, here are some ramblings about AOP that I pulled out of last week’s workshop:

 

Click to view a larger image

 

Aspect Oriented Programming Overview

 

Problem with regular development practices:

With traditional programming techniques, most code is highly coupled, complex and often there is much "administrative" repetitive code which makes system hard to maintain.  Or worse, in order to make to code less complex, such administrative code is totally left out.

 

Generally accepted good design practices state that a function should do one thing, and one thing only.  But often a function must do many additional tasks (aspects): logging, error handling, thread safety, etc.  This other "stuff" is often boiler plate code that is copy/pasted around all over the system.

 

What is AOP

AOP tries to fix this problem by separating these aspects out of the function into some sort of external construct.  The method is then decorated with these aspects in order to tell the runtime environment (or other external process) that they should be applied to the method at runtime. 

This way, the function's source code only does the one thing its supposed to do.

 

The concepts of what has become AOP started back in 1987.  Its goal is to modularize systems more effectively, which is nothing new.

 

Main AOP Terminology

  • Aspects: features of a program that do not relate to the core functionality of the program directly, but are needed for proper program execution
  • Cross cutting concerns: same thing as an aspect
  • Join point: point within a program where the aspect can be applied.  When the process in an application arrives at the join point of the program, the aspect is executed.
  • Point cut descriptor: one place in source that defines all places where join points are applied to the source.
  • Attributes: defines a single join point for an aspect in the source.  Standard way in .Net to decorate classes, interfaces, and methods with aspects
  • Weaving: the act of inserting calls to the aspect into the main program.  There are many ways to implement this.

 

Examples of how AOP can be used to solve some of these problems

  • Trace output
  • Logging
  • Checking for error conditions and acting accordingly
  • Dynamically generated asserts for method arguments
  • Transaction control
  • Exception handling (maybe)
  • Thread safety and coordination
  • State change and response mechanism
  • Singleton pattern mechanism
  • Business rule engine implementation (allows business rule logic to change dynamically without redeploying binaries)
  • encryption / decryption
  • Generate execution metrics
  • Custom security policy enforcement
  • Method pre/post processors (much like proxy classes)
  • Dynamically override a method (could use for deploying support patches.  Just deploy one aspect with one method.  The rest of the class stays the same)
  • Object instance pool management
  • Onsite client error debugging
  • Plug in architecture that customers could use to plug in their custom functionality to our product.

 

Almost all real world commercial implementations of AOP are in Java.  All (most?) .Net implementations of AOP are either designed through research groups or academia.

 

 

Simplified example of AOP:

Take the following 3 simple classes.

Point

X()

Y()

UpdateUI()

Line

Point1()

Point2()

UpdateUI()

Figure

Line1()

Line2()

Line3()

Line4()

UpdateUI()

 

When any code calls the X or Y property of the Point class, or the Point1 or

Point2 property of the Line class, it should call the UpdateUI method.  Or the X, Y, Point1 and Point2 properties could call UpdateUI themselves (as well as the Line1-4 properties of Figure).  But then you have duplicate code dispersed throughout the classes that does the same thing.  Not only that, but these properties shouldn’t really know about a UI at all.

 

The UI update logic could be pulled out into an aspect, which is then applied to the class.  At some point (depending on the type of AOP your

using) the AOP weaver would interrogate attributes and determine if any aspects should be executed or not.

 

Problem to watch out for would be unnecessarily duplicated calls to the aspects.  For example, what if the developer updates all 4 lines of class Figure?

UpdateUI could get called 28 times.  AOP engine should have ability to specify aspect execution rules along the call stack.

  

.Net'ish examples of limited AOP:

FileIOPermissionAttribute.  This does a stack walk to check for file IO permission.  You could put the code in each method, or just apply the attribute at the top of the method.  It keeps the method from getting cluttered

 

Problem with .Net and attributes:

Even though .Net has build in AOP style constructs, they are hard coded into the runtime.  If you define your own attributes, you must also define how and when those attributes are interrogated and used.  .Net does not have a generic way to hook into the runtime to say "When you come across this attribute, do this".

 

Different AOP implementation techniques

There are 4 main implementation techniques for AOP

 

1. Static source weaving:  The programming language is extended to include constructs for defining define aspects and where they get applied.  Before the language compiler gets executed, the AOP engine/compiler inspects the source code for aspects.  It then either inlines the aspect code into the method its applied to, or inlines a call to an aspect instance.  This altered source is then run through the language compiler and the resulting exe or dll is generated.  This has best runtime performance since compiler has a chance to apply optimizations.  This is how AspectJ works

 

2. Static byte weaving: The source is compiled through the normal language compiler.  Then an AOP weaver loads the dll/exe into memory.  It looks at the aspect mapping mechanism (this could be an xml file, a new language file like IDL, or attributes) and injects byte code into the dll/exe in the appropriate places to execute the aspect.  The dll or exe is then saved off to file.

 

3. Dynamic weaving: dll or exe is compiled through the normal language compiler.  At runtime, there is some mechanism that emits code into memory to execute the aspects at the appropriate place.  There are several techniques to do this.  One approach is to utilize class factories in order to create any instance of a class that has aspects applied to it.  The factory would emit into memory a new class that inherits from the class that is being requested.  Any method that has an aspect associated with it would get overridden, and contain calls to the aspects in the appropriate place.

 

One nice thing about this approach is that you can design an AOP to be able to dynamically bind, unbind and change bindings on aspects to join points. 

This means you can change application functionality without ever shutting down the application, which is important for long running server applications such as a database or web server.

 

4. Actually extend the runtime environment and the type loader to create classes with the aspects embedded in them.  This is fairly complex as it requires you to extend the CLR and JIT compiler.  This is the approach that JBoss uses with Java.

 

All of these have their good and bad points.  The first one gave you processor performance, but at the cost of no IDE support (in .Net) for the new language construct for defining the aspect bindings.  Static byte weaving gives you better IDE support, but can break some compiler optimizations because the aspects are woven post build (you have to turn off compiler inlining).  Dynamic weaving forces you to use class factories and code against interfaces for any class that has an aspect.

 

A fifth way (for .Net) to create an aspect weaver that I didn’t hear presented could follow these steps:

  • Post build, parse the binary assembly and recreate the entire assembly in a CodeDom object graph.
  • Anywhere the weaver found an aspect binding, it would inject the call to the aspect into the code via the CodeDom API.
  • Then use the C# compiler API to compile the CodeDom back to an assembly.
  • With this approach, you would have full IDE support because you would just use attributes or an external aspect mapping file.  You'd have full compiler optimizations because the woven code would be compiled again.  You don’t have to use factories and interfaces either.  Also, the CodeDom has debug symbol support, so you could update the debug symbols for the woven aspects.
  • The hard part would be to write a generic assembly to CodeDom mapping tool.

Where are aspects executed in the context of a method:

Aspects can get applied in three different ways: at the beginning of the method, the end of the method, or instead of the method.  This is usually specified on the attribute that decorates the method.  There is some cool work at creating an aspect definition construct to define where specifically in a method to apply an aspect.  For example, inside a loop, or in the else block of an if / else statement.

 

How are aspects bound to their target method:

There seem to be four camps on how to tag a method with an aspect.  With attributes applied directly to the method, class or interface (generally accepted .Net approach).  With a whole new extension to the language (JAspect approach).  And with an external file, such as an xml mapping file or a new language file much like how IDL was used with COM.  The fourth camp uses method naming conventions to tie the aspect to the method  (DoSomething_WithLogging_WithThreadSafety)

 

I like a combination of using Attributes and an xml file.  I think it’s important to have the visual queue when you’re coding that this method has an aspect applied to it.  But I like the dynamic flexibility that an external file could give you.  At runtime you could change the file to turn on or off aspects, change when they are executed, swap one aspect for another.

 

Other directions that use AOP:

There is another area of AOP that some people are looking at.  Instead of using aspects to separate concerns from the main functionality of a program, they are using aspects to extend existing dlls.  For instance, if you have a 3rd party dll, you could use static byte weaving to add fields, properties, methods and interfaces to the existing binary.

 

Problems with AOP:

  • All approaches have problems with debugger and IDE support.
  • One of the main ideas of AOP is that Aspects are hidden from most developers.  A problem with this is that it separates the aspects from the developers which can lead to problems.  What if the developer doesn’t know, or forgets, there is an aspect that will apply thread safety checking, or serialization tags?
  • Also, what about aspect priorities when multiple aspects are applied to the same methods.  Who is executed first?  Are there any considerations? 
  • It’s easier to see these issues when attributes are used to decorate methods with the aspects.
  • How do you find your failure points?  Is it the original source, the aspect source, or the AOP weaver?

Future of AOP in .Net and Microsoft:

Currently there seems to be about 30'ish different implementations of AOP available in various languages in .Net.

There doesnt seem to be any leading force withing Microsoft or the CLR team that is driving the integration of AOP into the CLR

 

Reading:

Aspect Oriented Software Development, Addison Wesley

 

Other stuff:

It was interesting to see that academic and pure research groups focus totally on "getting it to work".  But with very little regard to getting it to work easily.  They didn’t seem to realize that if the developer had to jump through lots of hoops in order to get the desired functionality, they most people wouldn’t use it.