Aspect oriented programming

Modularity of software is a great feature, the majority of this book has been about modularity and its advantages. However, there are some features of software that span the entire system. Security is a great example of this.

We would like to have similar security code in all the modules of the application to check that people are, in fact, authorized to perform some action. So if we have a function of the sort:

var GoldTransfer = (function () {
  function GoldTransfer() {
  }
  GoldTransfer.prototype.SendPaymentOfGold = function (amountOfGold, destination) {
    var user = Security.GetCurrentUser();
    if (Security.IsAuthorized(user, "SendPaymentOfGold")) {
      //send actual payment
    } else {
      return { success: 0, message: "Unauthorized" };
    }
  };
  return GoldTransfer;
})();

We can see that there is a fair bit of code in place to check if a user is authorized. This same boilerplate code is used elsewhere in the application. In fact, with this being a high security application, the security checks are in place in every public function. All is well until we need to make a change to the common security code. This change needs to take place in every single public function in the application. We can refactor our application all we want, but the truth remains: we need to have at least some code in each of the public methods to perform a security check. This is known as a cross-cutting concern.

There are other instances of cross-cutting concerns in most large applications. Logging is a great example, as is database access and performance instrumenting. Aspect oriented programming (AOP) presents a way to minimize the repeated code through a process known as weaving.

An aspect is a piece of code that can intercept method calls and change them. On the .Net platform there is a tool called PostSharp that does aspect weaving and, on the Java platform, one called AspectJ. These tools hook into the build pipeline and modify the code after it has been transformed into instructions. This allows code to be injected wherever needed. The source code appears unchanged but the compiled output now includes calls to the aspect. Aspects solve the cross cutting concern by being injected into existing code. Here you can see the application of an aspect to a method through a weaver:

Aspect oriented programming

Of course we don't have the luxury of a design-time compile step in most JavaScript workflows. Fortunately, we've already seen some approaches that would allow us to implement cross cuts using JavaScript. The first thing we need is the wrapping of methods that we saw in the testing chapter. The second is the tostring abilities from earlier in this chapter.

There are some AOP libraries already in existence for JavaScript that may be a good bet to explore. However, we can implement a simple interceptor here. First let's decide on the grammar for requesting injection. We'll use the same idea of comments from earlier to denote methods that require interception. We'll just make the first line in the method a comment that reads aspect(<name of aspect>).

To start we'll take a slightly modified version of our same GoldTransfer class from earlier:

class GoldTransfer {
  SendPaymentOfGold(amountOfGold, destination) {
    var user = Security.GetCurrentUser();
    if (Security.IsAuthorized(user, "SendPaymentOfGold")) {
    }
    else {
     return { success: 0, message: "Unauthorized" };
    }
  }
}

We've stripped out all the security stuff that used to exist in it and added a console log so we can see that it actually works. Next we'll need an aspect to weave into it:

class ToWeaveIn {
   BeforeCall() {
    console.log("Before!");
  }
  AfterCall() {
    console.log("After!");
  }
}

For this we use a simple class that has a BeforeCall and AfterCall method, one which is called before and one which is called after the original method. We don't need to use eval in this case so the interceptions are safer:

function weave(toWeave, toWeaveIn, toWeaveInName) {
  for (var property in toWeave.prototype) {
    var stringRepresentation = toWeave.prototype[property].toString();
    console.log(stringRepresentation);
    if (stringRepresentation.indexOf("@aspect(" + toWeaveInName + ")")>= 0) {
      toWeave.prototype[property + "_wrapped"] = toWeave.prototype[property];
      toWeave.prototype[property] = function () {
      toWeaveIn.BeforeCall();
      toWeave.prototype[property + "_wrapped"]();
      toWeaveIn.AfterCall();
    };
    }
  }
}

This interceptor can easily be modified to a shortcut and return something before the main method body is called. It can also be changed so that the output of the function can be modified by simply tracking the output from the wrapped method and then modifying it in the AfterCall method.

This is a fairly lightweight example of AOP. There are some frameworks in existence for JavaScript AOP, but perhaps the best approach is to make use of a precompiler or macro language.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset