Introducing Swiz AOP!
If you are currently using an Inversion of Control container, you have hopefully begun to take advantage of composition in your architecture. There are many articles out there on why IoC tends to favor composition over inheritance, so I won’t get into a long-winded discussion here, but I can say that when I began to use the Spring Framework for Java back in the early 2000s I really enjoyed learning to think of my applications as groups of shared services, composed of simple bits and peaces making up powerful work units. I play guitar and bass, and I like to think of what we call ‘Services’ existing in my application in a similar way as my effects pedals exist in my rig. If you unscrew a few, you will see that they are made up of a bunch of pretty similar components: capacitors, resisters, transistors and so on, but most users never look at that stuff. They see a few knobs, an input and an output or two. These are the effect’s interfaces. Most users don’t care how they work, they only care about the bad ass metal thunder sounds they make. To me this is a great way to think of application development, and IoC containers like Swiz are amazing tools to give you the power to compose your applications without much overhead, instead concentrating on real functional design. IoC is a great tool, but it’s really the power of composition that makes it all so elegant.
Aspect Oriented Programming in some ways is like composition on powerful mind altering drugs. Going back to my guitar analogy, some players like to add midi into their rigs. They put a special little device in the signal chain that can filter some or all of their sound into a box that, although it looks pretty much like any other guitar effect, can magically transform their guitar into entirely new and some may say interesting instruments. (Authors note: I do not condone this! There is absolutely nothing bad ass about an electric guitar sounding like a flute!!) What really interests me, though, is that the altered behavior is highly controlled, at runtime, by the player. This is what AOP does for your applications. It enables developers to selectively brush complex behavior into their applications, in an extremely transparent manner. So code that is already written, tested, and composed into a complete service can all of a sudden take on entirely new behavior. Sounds pretty awesome, no? Negative side? Well, that would be what I just wrote about ‘in an extremely transparent manner’. AOP can be hard to read, and even harder to understand how it’s even functioning in the first place. A core principle is dynamically changing objects in a way that objects using them can never know. It’s powerful, confusing, and wonderful all at the same time. As I said, it’s like an acid trip for your code.
So why would you ever do this? Let’s get on to what AOP really aims to acomplish. If you look at a complex system, it is often pretty easy to break it down into many, many specialized pieces of functionality, reused in few places, and far less specialized functionality reused in many places. The first group is your core functionality, the business logic you are trying to implement. The later group is stuff you need to redo all the time, and often can look at as being pretty coupled to code all over the place. In the AOP community, this type of functionality is referred to as ‘Cross Cutting Concerns’, because it cuts across so many parts of your app. The prime example of this is logging. Open up any big AS project and you will see either a ton of trace statements or logging statements everywhere. They cut across everything, but do they have anything to do with the actual business logic one line above them? No, because logging is not business logic, it’s simply cross-cutting debug logic. Other great examples are caching and security. Instead of in-line, right when you are about to make a remote object call, making a call to some security component to make sure the user is actually allowed to do whatever they are doing, then needing to write in logic to do whatever you need to do if they actually are not allowed, it would be much nicer to simply declare that method needs to be secured somehow. If you could simply say a component needs to somehow be secured, or have it’s results cached, you could then write code, very generalized and loosely coupled code, that would allow that component to take on a new aspect of behavior. You want that object to ‘be secured’ or ‘be cached’, sometimes, and need a means to configure that behavior instead of blindly inheriting it all the time. This is the primary problem AOP aims to solve. So how does it do that?
Well, although AOP uses terms like Proxies, Joinpoints, Pointcuts, Aspects, etc, which sound terribly confusing, I like to think about it in terms of Interception and Introduction. If I want to add security to a method, I am not going to actually write any code about security into that method. Instead I can use AOP to intercept that method, then at runtime decide if I would like to introduce the security logic before actually calling the method. The beauty is, you get very readable core business logic, and as long as you understand how the AOP part is configured, very reusable cross cutting logic to implement systems like caching and security. Since this is already a pretty lengthy article, I am going to leave you thinking a bit. In the next article I will provide a functional walk-through of AOP in practice with Swiz, showcasing a simple caching solution, then move on to a full discussion of Swiz AOP’s main principles. Check back, because these articles will come fast, I promise!