SAQL and SheepAOP Remake

SAQL?

Say hello to SheepAOP-Query-Language (hereafter referred to as ‘SAQL’), a new addition to SheepAOP, serving as the main language to query against your source-code for your SheepAOP pointcut definitions.

I know I said external-DSL would NOT be in my priority list, but the latest SheepAOP enhancement I was working on (outlined later) has made it strongly imperative that an external DSL needed to be brought onto the game, right now.

Initially, I took the path which follows the current trend in .Net libraries designs that have been increasingly moving away from external DSL in favor of lambda Fluent APIs. To name a few: NHibernate’s HQL taken over by NH2Linq, HBM by Fluent-NHibernate, Binsor by fluent-configuration, and I myself have also built lambda API in lieu of RhinoETL’s boo scripts. Lambda seems to be the new black. Therefore, at the beginning of SheepAOP project, it was very clear to me that Fluent lambda was the way to go about this whole AOP thing. With lambda API, I would get the intellisense and refactoring support from Visual-Studio, and I actively avoided the tedious effort of building an external DSL from scratch.

Over the weeks, I have been noticing few minor issues with lambda API that have been irritating me, albeit not to a point that bothers me enough to do anything about it.

  1. Safety. SheepAOP weaving is done during compile-time whenever you build your project. I have not been particularly happy about the fact that SheepAOP compiler needed to execute your actual application (i.e. your configuration routines) during compilation, as opposed to reading only its metadata. If you’re not careful, you might accidentally (or deliberately) execute certain unintended code-blocks (from within your config routine) during compile time, which might be harmful to anyone merely opening the project in their Visual-Studios. It makes it way too easy to abuse.
  2. File lock. Since your application are executed (by SheepAOP) during VisualStudio compilation, they would get loaded into your VS process, and will never get release (There’s no such thing in the .Net framework as “unloading” an assembly). It also means it will lock your output file, something you don’t want on an IDE. Spawning separate AppDomain normally solves this, but that doesn’t do the trick on VS custom-tasks for whatever reason. My current solution is to spawn a separate (console) process. Either way, lambda configuration makes communications difficult since they are not transmittable between AppDomains/processes. A plain DSL text-script, on the other hand, is.  Hence giving me a lot more flexibility in my approaches.
  3. Verboseness. Lambda API introduces too much noise for the signal. We will see this in comparison shortly.

Those are 3 minor drawbacks that I could happily live with, rather than spending my effort on an external DSL that could be spent elsewhere. Plus I was reluctant to give up IDE intellisense with fluent API.
But as I worked on the next enhancements (covered below), it quickly became obvious that fluent API no longer finds its place in the system, and I came to a tough decision to ditch the whole thing, and started working on a brand new querying language.

SheepAOP Enhancements

After exploring several common patterns and use-cases frequently seen on other more mature AOP tools like AspectJ, and then reviewed the current (previous) implementation of SheepAOP, I determined that the old SheepAOP design wasn’t up for the job. A total rework had to be done. The 3 major features that inspired the rework, which have now been delivered on the new version of SheepAOP, are:

  1. Aspect Lifecycle. This is a very important feature that single-handedly makes AOP useful in far broader sets of real-world problems. So far I have only seen this in AspectJ. I will post more elaborately on this one particular topic, but in essence, it allows you to determine the lifespan of your aspects, so you can maintain contextual states.
    For example, imagine you just defined a new client-facing method (say: MethodA) for your POS system, exposing a transactionTime as a parameter that the client (human or another app) can specify, so that all sales-order objects constructed at any point within the scope of that method will be initialized with this transaction-date. Normally this means that you will have to pass this date from MethodA all the way through all methods beneath its flow, to be used in every sales-order instantiation it reaches.
    With PerFlow lifecycle (new!), you can define that your aspect’s life will start when the MethodA starts. It will then begin intercepting all sales-order instantiations within the flow, and assign them with the transaction-date (captured from before). When MethodA completes, this aspect will also be disposed out of the way, which also ends its intercepting business. With a pseudo-code, your aspect looks like:

    [Lifecycle (PerFlow of "MethodA_called")]
    aspect TransactionDateAspect:
    {
       // Normal instance field, stays here within the life of this aspect object
       private Date _transactionDate;
    
       pointcut MethodA_called;  // The "life trigger" for this aspect, as declared on the top
       pointcut SalesOrder_instantiation;
    
       [Before(MethodA_called)]
       void OnMethodA_called(Date transactionDate)
       {
           // Aspect initiates here. Let's keep the transaction-date within the context
           this._transactionDate = transactionDate;
       }
    
       [After(SalesOrder_instantiation)]
       void  SalesOrder_instantiation (SalesOrder order)
       {
          // This advice is only active within the life of this aspect
          order.TransactionDate = this._transactionDate;
       }
    }
    

    This ability enables you to compose an aspect-oriented workflow. There are many other lifecycles, for example: PerTarget aspects allow you to cache method-calls to the same object instance. PerThis allows you to keep all dirty states within that instance. Singleton and Transient are the other options.
    The reason this could not be done on the previous SheepAOP design was because all advice-methods had to be static since they merely acted as code templates to be copied to the injected targets (which also causes the problem in point#3).

  2. Inheritance, Polymorphism, and Abstract Aspects. Now that we have aspects and pointcuts as normal living instances (as opposed to a bunch of static instruction templates), you can use inheritance and polymorphism around your aspects for reusability and extensibility. For instance, you can define the following abstract aspects (this one is an actual SheepAOP code):
    public abstract class LoggingAspectBase
    {
       protected abstract string Title();
    
       protected abstract void LoggablePointcut(); // Override your pointcut here!
    
       [Around("LoggablePointcut")]
       public object LogExecution(JoinPoint jp)
       {
          try
          {
             _logger.Log("Entering {0} with [{1}]" + Title(), jp.Args);
             var result = jp.Proceed();
             _logger.Log("Returning {1} from {0} " + Title(), result);
             return result;
          }
          catch(Exception e)
          {
             _logger.Log("Error on {0}: {1}", Title(), e);
          }
       }
    }
    

    And you can reuse this base-aspect class by simply implementing it.

    public class OrderSubmissionLogging: LoggingAspectBase
    {
       protected override string Title()
       { return "Order Submission"; }
    
       // Overriding your pointcut
       [SelectMethods("Name:'SubmitOrder' & InType:(Namespace:'Sheep.Sales.*')")]
       protected override void LoggablePointcut(){}
    }
    
  3. No method-copier, means better debugger. As explained in the previous posts, the old SheepAOP used your advice-methods as a code-template, in a literal sense, copying the body line by line to surround the target code-blocks. (Think T4). Because your advice-methods were only templates and never got executed, it naturally means your debugger would never arrive there. I suggested event-based advices to “solve” that, which I have to admit, a bit clunky, unpredictable, and error-prone.
    The new SheepAOP will no longer employ this “code-template” technique. It now makes use of .net delegates. SheepAOP now pulls your code-blocks into statically-generated methods, and keeps the delegates of them, so your application will literally jumps back and forth between these delegates. Your debugger will be able to cope with that. It also means that you can even make your advice call your target methods several times. E.g.:

    public int Advice(JoinPoint jp)
    {
       var returnValue= jp.Proceed();
       returnValue+= jp.Proceed();
       returnValue+= jp.Proceed();
       return returnValue;
    }
    

    That advice would execute your target methods 3 times, and yup, this time is for real: your advice method actually gets executed during runtime. When you call jp.Proceed(), beneath the skin it will simply make a delegate call that points back to your hidden underlying target code-block.

These changes demanded a major change. I had to rewrite the project pretty much from scratch. How does this affect Fluent API? Let’s see.

The shift from static advices and pointcuts into active instances (especially to support inheritance at point#2) means that SheepAOP will now have to instantiate your actual aspect classes in order to execute its configuration routines (and their inheritances). The same aspect classes that are also used during the runtime.
I don’t like this. Your classes typically have certain instantiations routine required during the runtime (e.g. application-settings, dependency-injects, even sometimes database-connections). The fact that now I have to execute the same runtime routines as part of my compilation process really bothers me. And once you get the actual runtime instance of your object, it really becomes inevitable to make “accidental” abuse within your AOP configuration code. It was aggravated by the ever swelling number of generics tags and lambda arrows noise thanks to the fast growing need for a more expressive configuration system, I eventually determined that this is a good time for the birth of SAQL.

SAQL!

Ok, this will be brief. I’ll just give a comparison of the same pointcut between the old syntax and the new one. I will deliberately use a dreadfully complex example to magnify the difference.

Old Fluent API:

[RegisterPointcut]
public static void MyPointcut(PointcutRegistry reg)
{
   reg.Advise(r=> r.Method(m=>
      m=> m.Name("Save").And(m1=>
            m1.IsStatic(true)
            .DeclaringType(t=> t.Namespace("Sheep.Data.*"))
            .Arg(t=> t.Any())
            .Arg(t=> t.AssignableFrom(i=> i.FullName("NHibernate.ISession")))
         .Or (m2=>
            m2.IsStatic(false)
            .DeclaringType(t=> t.Implements(i=> i.FullName("Sheep.IRepository`1")))
           ))
      ), MyAdvice);
}

SAQL:

[SelectMethods(
    @"Name:'Save' &(
       IsStatic & InType:Namespace:'Sheep.Data.*' & Args:( , (AssignableFrom:'NHibernate.ISession'))
       || !IsStatic & InType:Implements:'Sheep.IRepository`1'
      )"
)]
public void MyPointcut() {}

The 2 codes above are querying exactly for the same pointcuts, resulting in exactly the same joinpoints. But I believe the second one using SAQL is much easier on eyes. The noise is kept minimum in the syntax. That SAQL query will then be lexed, parsed, and walked using ANTLR3 into a workable AST, that’s in turn translated into SheepAop Pointcut objects, ready to crunch your assemblies (fed by mono-cecil) to find the matching code-blocks within your assemblies.

As for the grammar, I actively avoided using words as part of the syntax (like in SQL and HQL) , because even though it makes it easier to read, it makes it harder to write. You might sometimes find yourself wondering whether you have to use ‘where‘, or ‘is‘, or ‘not in‘, or ‘is not in‘ in specific instances. I believe a consistent use of small number of punctuations makes for a more intuitive experience. But I’m open to feedback regarding the language grammar.

Where’s The Stuff?

No surprise here, everything is in the Codeplex repository (http://sheepaop.codeplex.com/). I haven’t produced a release for this yet since this is still very unstable, especially in the error-detection department (EDIT: and Generics situations, which is unexpextedly very tricky).

I will post next articles to explore the various features I’ve only briefly alluded above:

  • SAQL basics
  • Abstract aspects and polymorphism
  • Aspects lifecycle (real world examples of “contextual aspects”)
  • Aspect factory (connecting your beloved IoC to SheepAOP)
  • Debugging tips

Announcing SheepAOP (Part 2)

This post is the excerpt from yesterday’s presentation about the new SheepAOP project that I’ve just started recently.
All code exercises in this post can be found under SheepAop.Samples project as part of the SheepAop repository (http://sheepaop.codeplex.com/)

Part 1 – AOP for Everyone
Part 2 – SheepAOP Basics

Some Arbitrary Application

We need to start somewhere, so why not from this simple meaningless code?

class Program
{
    static void Main()
    {
        IoCConfig.Bootstrap();

        var result = "Elephant".CalculateAdsFee(10);
        Console.WriteLine("Index: {0}", result);

        Console.ReadLine();
    }
}

public static class StringHelper
{
    public static int CalculateAdsFee(this string text, int rate)
    {
        Console.WriteLine("Calculating {0}... ", text);
        if(text.Length < 15)
            return text.Length*rate;

        Console.WriteLine("Maximum fee!!");
        return text.Length*rate + 15;
    }
}

image

No surprise there. 8 characters in “Elephant”, charged at $10 rate, calculates into $80.

Your First Aspect

Now let’s create a pointcut to target StringHelper.CalculateAdsFee(string, int) method above. In this case, I’ll say all methods beginning with word “Calculate”, declared within any type ending with word “Helper”:

public static class DemoAspect
{
    [RegisterPointcut]
    public static void CalculateFeePointcut(PointcutRegistry reg)
    {
        reg.AddCurrentAssembly().Advise(m => m.Method
            .Name("Calculate*")
            .DeclaringType(t => t.Name("*Helper"))
            , DemoAdvice);
    }
}

We have our pointcut, and as you see, we advise it with “DemoAdvice”, which doesn’t exist yet. So let’s create one now (visual-studio or resharper will help you with this).

private static void DemoAdvice(MethodJointPoint jointpoint)
{
    Console.WriteLine("Demo advice for {0} from {1}", jointpoint.Args[0], jointpoint.Method);
    jointpoint.ReturnValue = 10000;
    Console.WriteLine("Leaving demo advice");
}

This method will never get executed. It will only be interpreted at the compile time to decorate your original StringHelper methods.

What we’ve just done there in this case, is that we have swapped completely the body of our original StringHelper method with these 3 lines of code we have just introduced in our advice. This is a crude way of creating an advice, we’ll see later a gentler way of doing this. But for now, let’s see the result:

image

Let’s see with the debugger, and keep hitting F11.

image
image
image

The execution jumps straight out from the CalculateAdsFee method, and returns 10000 immediately. This is because the whole method body of CalculateAdsFee() is no longer there, as we instructed SheepAOP to replace it with the new content, which simply returns 10000.

That’s rarely what we want. So let’s now change our DemoAdvice to the following:

private static void DemoAdvice(MethodJointPoint jointpoint)
{
    Console.WriteLine("Demo advice for {0} from {1}", jointpoint.Args[0], jointpoint.Method);
    jointpoint.Args[0] = "Sheep!!";

    JointPoint.Proceed(); // LOOK HERE!

    jointpoint.ReturnValue = (int) jointpoint.ReturnValue + 100;
    Console.WriteLine("Leaving demo advice");
}

JointPoint.Proceed() on line#6 only contains “throw NotSupportedException” if you execute it. But that’s fine because advice methods never actually get executed. Only intepreted as a template during compile time.
JointPoint.Proceed() is a keyword that will be used by SheepAop compiler as a marker that that’s where the original method body should go. So if we run the application again, we’ll get:

image
image

image

image

image

image

Between step#2 and step#3, you can see that the parameter text changes its value magically from “Elephant” to “Sheep!!”. On step #4, the method was returning 70*10=70, but the actual return value immediately changed to 170 on step#5. These behaviour changes are caused by the advice what we specified earlier: we change args[0]=”Sheep!!”, and we also increment the ReturnValue by 100 (hence resulting in 170).

You have seen the basic of what you can do with Advice. You can do pretty much what you can with a normal code. You can check if a value is within a certain range, and alter the flow of the execution.

Altering Specific Lines Of Code

This example will seem a bit crazy, that’s because I am using an incredibly unrealistic example, just to demonstrate the kind of thing you can do with SheepAOP. Here’s the initial code:

class CrazyProgram
{
    static void Main()
    {
        IoCConfig.Bootstrap();

        string str = null;
        Console.WriteLine("Index of z: {0}", str.IndexOf('z'));

        Console.ReadLine();
    }
}

That line#8 is surely going to crash spectacularly, and rightly so.

imageimage

Even if we put an aspect inside of the string.IndexOf(char) method, that won’t help since the method won’t even get called in the first place.

So instead, let’s now write a SheepAOP aspect to target that specific line of code.

public class CrazyAspect: IAspect
{
    [RegisterPointcut]
    public static void CrazyPointcut(PointcutRegistry reg)
    {
        reg.AddCurrentAssembly().Advise(r=> r.Instruction
            .MethodCall(
                m=> m.Name("IndexOf").DeclaringType(t=> t.Is()))
            .ExecutedIn(
                m=> m.DeclaringType(t=> t.Is())
            ), CrazyAdvise);
    }

    private static void CrazyAdvise(MethodCallJointPoint jointpoint)
    {
        jointpoint.TargetInstance = "crazy";
        JointPoint.Proceed();
    }
}

So there, we create a pointcut to target a specific instruction line in the code. There are several types of instruction we can target, for example, setting a field, getting a field, “new” instantiation, equality comparison, etc, but in this case, we want to target the “method call to string.IndexOf(char)” from any line of code “executed within any method in the CrazyProgram class”.

PS: The ExecutedIn() criteria can be handy to define different advices for a particular instruction executed from different contexts. For example, we can define that when we call “new Customer()” from within the VIP area, then we will return a new instance of VIPCustomer instead.

Now if we execute the application again, we’ll get:

imageimageimage

This time, the line passed through successfully, even though the str value is still null. What happens here is that we have just redirected the call to string.IndexOf(‘z’) method to an instance of string value “crazy”, rather than its original null instance, and hence returning 3 (the index of ‘z’ in ‘crazy’).

That was a silly example, but it shows you how you can use SheepAop to reach virtually any part of your code. Not only methods and properties.

Event Driven Aspects

I do NOT recommend you writing advices using the approaches I have been using in all previous examples. There are 2 disadvantages of it:

  • Your advice will get welded straight to the target assembly, meaning that you won’t be able to change your advices dynamically at runtime
  • Since your advice methods are copied across during compilation, and never actually gets called, you won’t be able to follow it with debugger. There’s too much invisible surprises involved, which is why I strongly discourage this approach. For instance, if you look back to your first Aspect that we wrote, our debugger shows some invisible magic at the beginning of your method that changes your “Elephant” into  a “Sheep”.
    image
    image

There is an extension method on the PointcutRegistry to alleviate this problem. It’s called: Listener. Now let’s change our DemoAspect from our first example to the following:

public class DemoAspect: IAspect
{
    [RegisterPointcut]
    public static void CalculateFeePointcut(PointcutRegistry reg)
    {
        reg.AddCurrentAssembly().Listen(m => m.Method
            .Name("Calculate*")
            .DeclaringType(t => t.Name("*Helper")));
    }

    public void Init()
    {
        var listener = Listener.Method(CalculateFeePointcut);
        listener.OnEntry += (j, c) =>
        {
            Console.WriteLine("Demo advice for {0} from {1}", j.Args[0], j.Method);
            j.Args[0] = "Sheep!!";
        };
        listener.OnExit += (j, c) =>
        {
            j.ReturnValue = (int)j.ReturnValue + 100;
            Console.WriteLine("Leaving demo advice");
        };
    }
}

You’re not actually losing any functionality. You can do almost anything you could do with the old way. There are 3 events you can subscribe to: OnEntry, OnExit, and OnException.
Now if you run the debugger again, you will get the following:

image
image

image

On step#2, the debugger steps through your event handler, where you can inspect all the runtime details about the jointpoints. Now you can see everything that is going on. There’s no more code that’s not visible from the debugger.

And since your advice is now event-driven, you can subscribe and modify your advice at runtime however you like.

You can, for example, use plugin architecture to attach to these events to affect the intimate behaviour of your application dynamically. This is normally done using MEF or IoC using some sort of service-location pattern that you put in place in your application as a set of predefined extension points. AOP offers a less intrusive way of doing it, where you are not forced to reshape your architecture in any specific way to allow an injection of dynamic behaviours to your application via plugins and events. CQRS is another exciting possibility (where your reporting-context would unobstrusively subscribe to specific “pointcuts” within your domain-models).

Sometimes you still need to use the plain Advice, usually if your advice is surrounding your pointcut, for example: stopwatch to time around your pointcut, transaction-scope, or disposable objects. But when you do need to use Advice, try to extract out all logic into a separate public method. Remember that only the content of your Advice method gets copied across. So if you put your logic in a separate method, you will be able to use debugger on it. So only use the Advice method to declare control-flow, and leave any logic out. Try to keep your advice as lean as possible, and you’ll get as little surprise as you can afford.

Shopping Cart

Finally, to refresh our memory, here’s the aspect example from our previous post about the shopping-cart.

public class PurchasingNotificationAspect: IAspect
{
    [RegisterPointcut]
    public static void SetProductPointcut(PointcutRegistry reg)
    {
        reg.AddCurrentAssembly()
            .Listen(r => r.Setter(p => p.StockQty));
    }

    private readonly INotificationService _notifier;

    public PurchasingNotificationAspect(INotificationService notifier)
    {
        _notifier = notifier;
    }

    public void Init()
    {
        Listener.PropertySet(SetProductPointcut).OnExit += (j, c) =>
        {
            if ((int)j.Value < 5)
                _notifier.Send(Notice.Restock, (Product) j.Instance);
        };
    }
}

Setup

To You need to attach SheepAop compiler to your project (containing your aspect definitions) to weave your assemblies (any assembly, doesn’t have to be the project assembly itself). For example, our SheepAop.Samples project has the following lines defined in its csproj file. You will need to do the same for any project using SheepAOP aspects.

<PropertyGroup>
   <SheepAopLocation>$(MSBuildProjectDirectory)\Libs</SheepAopLocation>
</PropertyGroup>
<UsingTask TaskName="PostCompileWeaveTask" AssemblyFile="$(SheepAopLocation)\SheepAop.Tasks.dll" />
<Target Name="AfterBuild">
   <PostCompileWeaveTask TargetFile="$(MSBuildProjectDirectory)\$(OutputPath)$(MSBuildProjectName).exe" Namespace="SheepAop.Samples.*" SheepAopLocation="$(SheepAopLocation)" />
</Target>

Where to Next?

In very near future, these are the things that will keep me busy:

  1. Mixin support
  2. Support for Attribute style aspects
  3. Add more aspect supports for many other IL constructs (e.g. c# “new” keyword, constructors, ==, etc).
  4. Groking AspectJ

What I’m not gonna do (but would love if anyone could help):

  1. External DSL (ala AspectJ)
  2. IDE integration (background analysis and indexing to speed up compilation time)

Feedback?

This project started as my learning attempt. I’m happy with all the learning gained in the past few days around IL, Mono.Cecil, and AOP in general. I’m still learning and experimenting with this project, and I am looking forward to hear any feedback and advice. I’ve put all the source-code out there, so feel free to explore, scrutinize, and I’d be pleased to hear any area that can be improved, both in the coding department (maintainability) as well as performance.

And of course, any contribution will be more than welcomed.

Download

You can download the full source-code of SheepAOP and all examples in this post (and the previous post) in the SheepAop main repository in Codeplex (http://sheepaop.codeplex.com/).

Announcing SheepAOP (Part 1)

Not the wittiest name, I realize, but certainly among the top in the cuteness league. SheepAOP is yet another AOP tool for the .NET environment (which frankly aren’t that many). It uses IL weaving to inject croscutting concerns to your dll at compile time. (And soon, SheepAOP will also support IL weaving at assembly load-time as an alternative, leaving the original dll intact).

The project is still in its very early inception, it just started last week, so I’m all ears to as many feedbacks as I can get.
I did a presentation on this yesterday, which I’m going to recap here in this 2-part-series.

Part 1 – AOP for Everyone
Part 2 – SheepAOP Basics

AOP for Everyone

SheepAOP project is driven primarily by experimental intents, but its ultimate goal is to make AOP more accessible for .NET developers.
In today’s climate, when we talk about AOP, we normally would only use it for things of the grandest scale, like transaction-management, logging, security authentication, and all that sort. But there are many trivial things in our everyday work that we won’t immediately think of AOP. In those instances, we usually feel like we need an intensely compelling reason before we even think about resorting to AOP. I think this is down to the lack of the tooling, especially in the .Net space, where AOP has become something highly exotic.

This is what I intend to change, by bringing in a free alternative onto the table, making AOP a bit more accessible that hopefully people would just go ahead and start writing aspects for simple things without thinking much about it, just like what people do in Java for instance, where AspectJ has become a defacto standard, so ubiquitous that whenever you sense the slightest need for an aspect, chances are you already have AspectJ within your library stack, so you just go ahead and write your aspects.

Simple Everyday Thing

Nothing is simpler than the cliché Shopping Cart example, a bare one notch above Hello World. So let’s use this as our example.

public class ShoppingCart
{
    public void AddProduct(Product product, int qty)
    {
        product.StockQty -= qty;
        _items.Add(new CartItem(product, qty));
    }
}

public class Product
{
    public int StockQty
    {
        get { return _stockQty; }
        set
        {
            _stockQty = value;
        }
    }
}

A clean simplistic shopping cart class. But life as a developer is never this clean and simple. In fact, the customer just came with a new Notification rule, specifying that:
“If StockQty drops below 5, then send a notification email to the Purchasing Department to restock the product.”

So we’re going to carry out that rule whenever the StockQty property is set (line #17). So what are we gonna need? Firstly, you’ll obviously need an INotificationService in the Product class, and the ShoppingCart is going to supply that, all the way from the top where you meet your IoC container.

At this point, you would not normally think of AOP. You would instead employ a more conventional approach by rearchitecting your domain structure. You use the good old Dependency-Injection, and introduce double-dispatch pattern around your methods.

public class ShoppingCart
{
    public void AddProduct(Product product, int qty,
                    INotificationService notifier)
    {
        product.ReduceStock(qty, notifier);
        _items.Add(new CartItem(product, qty));
    }
}

public class Product
{
    public void ReduceStockQty(int qty, INotificationService notifier)
    {
        _stockQty -= qty;
        if(_stockQty < 5)
            notifier.Send(Notice.Restock, this);
    }
}

So we changed the StockQty property into a method so we can inject a new dependency, which is passed all the way through shopping-cart up to the top, which depending on your object structure, may be quite deep. You have to make the same change to all places that use the StockQty property to accommodate the new dependency. This is an example of one simple change that make a great impact to the source code.

There’s no problem with this approach, we use this pattern everyday. But let’s now shift our thinking a little bit.

The main drawback of this approach is pollution. Let’s ask ourselves: does this piece of code really belong here? It doesn’t seem right to me. What’s a warehouse purchasing policy doing in a Product class? It is completely unrelated to the business of putting a product into your shopping trolley. And why do we need an INotificationService to use a shopping-trolley anyway? We certainly don’t send any notification email when you chuck a product into the trolley, but the service is just there to cover a specific edge-case scenario that might or might not happen somewhere down the line of the executing flow. If it only happens occasionally, why do we have to pass the notification-service every time? That seems to put a lot of unnecessary garbage to our otherwise clean code.

In typical projects, these edge-case-scenarios are usually quite plenty. There are usually a vast number of combinations of all different possibilities that we need to cater for, e.g. apply extra tax if the customer is within certain countries. Our code starts to look like transaction-scripts of various if-else conditions. Our classes are becoming less and less about shopping-carts and products; and more and more about different bits and pieces of all unrelated concerns, glued together to cover all possible basis.

What about all other notification alerts? Every time the customer define a new notification-template, we need to open our application source-code, look in our domain classes where we can fit the logic in, and implant the notification condition right there, and rewire all the required dependencies. We do that for each of our notification rules, and the whole notification policy is those pieces of logics scattered all over the source-code. Every time we define a new one, we need to remodify our domain source-code again. Each of our classes now has a lot more than one reason to change. Any class can change any time for any reason, and none of them can seem to escape from it.

Say Hello to SheepAOP

Let’s see an alternative way of implementing the same requirement. Let’s rewind back to the start.

public class ShoppingCart
{
    public void AddProduct(Product product, int qty)
    {
        product.StockQty -= qty;
        _items.Add(new CartItem(product, qty));
    }
}

public class Product
{
    public int StockQty
    {
        get { return _stockQty; }
        set
        {
            _stockQty = value;
        }
    }
}

These are our classes when they were still neat and clean. Everything about shopping-cart and product, and nothing else. So now, what’s the first thing that we’re going to change on these classes?

Right, the answer is nothing. We are not going to touch these classes. They already do all they’re meant to do, so leave it that way, keep them clean and simple, and don’t pollute them with any other garbage.

Instead, we are going to create a new class, let’s call it WarehouseNotificationAspect.

public class PurchasingNotificationAspect: IAspect
{
}

This class can be defined completely separate from your actual classes. Anywhere you want. You can even place this in a separate project, let’s say, Sheep.NotificationPolicy project, if you like.

Now let’s define a “pointcut”. If you’re not familiar with the terminology, don’t worry we’ll get there in no time. For now, you only need to know pointcut as a “criteria to search within your source-code”. In our case, we want to target the setter of our “Product.StockQty” property, so let’s write our pointcut for that.

[RegisterPointcut]
public static void SetProductPointcut(PointcutRegistry reg)
{
    reg.AddCurrentAssembly()
        .Listen(r => r.Setter(p => p.StockQty));
}

Now that we have our pointcut, we can offer an “advice” to it. We can say: “when this ‘property is set’ (PropertySet), after ‘it’s done’ (OnExit), please ‘do this and that’”.

public void Init()
{
    Listener.PropertySet(SetProductPointcut).OnExit += (j, c) =>
    {
        if ((int)j.Value < 5)
            _notifier.Send(Notice.Restock, (Product) j.Instance);
    };
}

During compile time, SheepAOP will insert these extra logic at the end of the StockQty property, and save it to your dll.

Since this aspect class is just a normal POCO class, it means you can just manage this using your normal IoC container, so you will have all your dependencies sorted. The full source-code of our aspect becomes:

public class PurchasingNotificationAspect: IAspect
{
	[RegisterPointcut]
	public static void SetProductPointcut(PointcutRegistry reg)
	{
		reg.AddCurrentAssembly()
			.Listen(r => r.Setter(p => p.StockQty));
	}

	private readonly INotificationService _notifier;
	public PurchasingNotificationAspect(INotificationService notifier)
	{
		_notifier = notifier;
	}
	public void Init()
	{
		Listener.PropertySet(SetProductPointcut).OnExit += (j, c) =>
		{
			if ((int)j.Value < 5)
				_notifier.Send(Notice.Restock, (Product) j.Instance);
		};
	}
}

Your original ShoppingCart and Product classes remain untarnished, so you can unit-test them easily as a plain shopping-cart without having to worry about other unrelated concerns and depedencies. Similarly, you can unit-test your notification-policy in isolation by testing your notification-aspects.

Jargons

Let’s review our jargons.

  1. Pointcut: Search-criteria of what you want to influence with your aspect. We had a very simple pointcut in our previous example, but pointcut can be very sophisticated. I’ll give an example using a pseudo-code with a language we’re all familiar with: SQL.
    select from all [methods] where
    	(methods:
    		is public or protected &
    		Name like ‘Get*’ | ‘Find*’ &
    		Returns (all types:
    			IsAssignableFrom (Money or Number)) &
    		Declared in (all types:
    			namespace: is ‘Sheep.Domain.*’ &
    			Implements(type: Name like ‘I*Service’)) &
    		Args is (int id, ..., string *name, )
    	)
    

    We were selecting all methods where it’s public or protected, with a name beginning with Get or Find, returning any type assignable from Money or Number, declared within any type within the ‘Sheep.Domain.*’ namespace, and implements any ‘I*Service’ interface, with arguments of yada yada yada.

    We can search not only methods and property. We can even search a specific-line-of-code! Such as this one.

    select all [instructions] where
    	(field: Product.‘_stock*Qty’ &
    		type: int or double
    	) &
    	instruction: Executed within
    	(method:
    		Name(‘Change*’) &
    		Declared in type: ShopingCart
    	)
    

    Just to give an idea of what pointcut does, let’s see one in action. I need to use an example from Java, because quite frankly I could not find anything from .Net that is even remotely comparable to AspectJ. So here’s AspectJ on Eclipse IDE.

    PS: AspectJ is an ambitiously sophisticated AOP framework, and SheepAOP is no where near it in any possible way. But the maturity of AspectJ makes for an excellent example to give you a good idea about various AOP concepts.

    image
    (Image #1, AspectJ Pointcuts)

    Unlike anything on .Net, in AspectJ aspect is a first-level language construct. So see on the left pane, we have an aspect that declares an annotation using pointcut * Account+.*(..), i.e., all methods within Account class with any name and any arguments. The right pane instantly shows you that 3 methods are affected by this pointcut. These 3 methods are your croscutting concern that you want to target with your aspect. You can even visualise these pointcuts within the IDE.

    image
    (Image #2, AspectJ Pointcuts Visualisation)

    On the right pane, you see your pointcuts, and the main panel shows you how each of these pointcuts crosscuts through your source-code. Imagine the blue one as our Notification Policy. We can see various places where we put some specific logic to send notification emails based on certain conditions. We can create an aspect for this so we don’t pollute our source-code with anything that’s not related with the actual business of your application.

  2. Jointpoints: The “search result” of your pointcut. Those 3 methods on the right pane of Image#1, we can see our Pointcut matches with 3 jointpoints (the validate(), credit(int), and debit(int) methods)
  3. Advice: Once we have our pointcut, we can offer it some advices of how those pointcuts should change their behavior (i.e. logging, start-transaction, authorisation, etc).
  4. Aspect: We have our pointcut, we offer it some advices, we have an Aspect.Here’s another example from AspectJ of a complete Aspect.
    image
    (Image #3, AspectJ Aspect)We have a complete AspectJ aspect. We define a pointcut to target all public methods under Account class (with any name and arguments), and we offer it an advice that “before” you execute the method, please authenticate the “account”, where “account” is the owner (aka the ‘this’) of the method.

Different Flavours

There are few different ways we can do AOP:

  1. Code Generator
    e.g. T4, CodeSmith
  2. Dynamic Proxy
    e.g. (Castle DynamicProxy), Spec#, NAspect
    This is by far the most popular AOP approach in .Net, which is unfortunate as it’s also the most limited way of doing AOP of all. It can only be used for objects managed by IoC, then its virtual/interface requirement, no static-methods, etc, making it hardly useful for too many purposes.
  3. .Net Profiller API
    e.g. TypeMock Open AOP (CThru).
    .Net profiler API’s use in production environments is strongly discouraged, although how bad we’ll get punished for violating it still remains unclear.
  4. IL Weavinge.g. AspectJ, PostSharp, and SheepAOP
    This is the most popular approach outside the .Net circle.

Why Another One?

PostSharp is an excellent product and has done remarkably well over the years, but one of my primary reasons of my reinventing it with SheepAOP (apart from to offer an open-source alternative) is down to the difference in style. PostSharp puts a huge emphasize on the use of .Net Attributes. The problem of Attributes in AOP is that the attribute itself becomes the repetitive crosscutting concerns. In contrast, SheepAOP firmly sticks on the well-known AOP pattern and terminologies using pointcuts, jointpoints, and advices, although the use of attribute will also be supported soon.

(.. more about SheepAOP in part 2)

Summary

SheepAOP is an open-source AOP framework, still in its early inceptions, that aims at bringing the classic AOP style and patterns to the .Net audience. The framework uses IL weaving (thanks to Mono.Cecil) to inject croscutting behaviours during compile-time.

In this post, we’ve discussed about how aspects can be used to help everyday’s domain-driven applications, beyond the highly clichéd transactions and logging.

The next post (part 2) will cover the basics of using SheepAOP.

The SheepAOP project repository and source-code of this post can be found in Codeplex: http://sheepaop.codeplex.com/