PostSharp 2.0: Design Objectives

by Gael Fraiteur on 04 Sep 2009

Before starting to blog about new features of PostSharp 2.0, it's good to remind the design objectives of this release.

Stated in one sentence: PostSharp is the leading aspect framework for .NET and will remain.

This was already true with PostSharp 1.5. In next version, the distance between PostSharp and other frameworks will be huge. You will judge by yourself in next posts.

Backward compatibility

As everyone knows, being the leader comes with greater responsibilities. And the responsibilities that lay on the shoulders of a framework are harsh. People working in Microsoft or Sun could easily confirm it: once your framework starts being widely used, maintaining backward compatibility is not optional. Every design decision will have consequences years later. And design errors can have catastrophic consequences for the community.

A framework differs from a library in the fact that a library is intended to be used, whereas the framework is intended to be extended. Designing a framework that is both highly extensible and prepared for backward compatibility is very challenging. As the framework developer, we have to be very specific about our supported extension points, and make sure that additional functionalities can be exposed through these extension points without breaking binary compatibility.  

PostSharp 1.5 was designed to be "approximately backward compatible" at source level. It took the assumption that, as the aspect developer, you can spend a few minutes making minor fixes in your source code when you upgrade. However, this works only because you are the developer of the only aspects used on your computer.

Now, what if you get aspects from other vendors? Say you are using DataObjects.NET 4.0 (DO). It comes with its own PostSharp aspects. Can you use upgrade PostSharp at will? No, you will have to use the version DO was compiled for. Now what if you use also aspects from Log4PostSharp? What if two vendors compile using different versions of PostSharp? Most probably, it would break. As you can see, approximate source-level compatibility is not enough when you develop a framework that can load plug-ins from multiple vendors (something that Linux kernel developers have never understood).

Being the leading aspect framework for .NET, many vendors will want to deliver aspects for their own products - based on PostSharp. So these vendors will have the possibility to redistribute PostSharp with their own products, and get very attractive commercial conditions to do so (much more attractive to small companies than for PostSharp 1.5). But what if a user upgrades PostSharp after having installed a third-party plug-in? The plug-in would be executed in a version of PostSharp that is more recent than the one it has been designed for. But it will have to work! And it will, because it has been engineered to.

Dependency Solving

Backward compatibility is just one requirement brought by the multiple vendor scenario.

Another issue is dependency solving. Say that vendor A delivers a caching aspect and vendor B an authentication aspect. Clearly, authentication should always be checked before the cache look up is performed. How to express this dependency if A and B don't know about each other? In PostSharp 1.5, dependencies are solved by setting the priority of aspects using an integer value. This works right when the team is in charge of all aspects, but it clearly does not scale to larger teams or multi-vendor scenarios. So PostSharp 2.0 comes with a brand new symbolic dependency engine based on topological sort. The dependency engine is able to detect conflicts between aspects and dependency cycles. This engine is actually at the heart of the new architecture.

Large Vision of AOP

Because it needs to be backward compatible and extensible in the future, PostSharp 2.0 also needs to implement a large vision of aspect-oriented programming.  PostSharp 1.5 implemented a rather small subset of the features offered by AspectJ. It would not have been possible to implement AspectJ based on PostSharp Laos. Even if PostSharp 2.0 does not implement all the features of AspectJ, I am quite confident that it would be possible in to do so.

PostSharp 2.0 will already support method interception, property interception, field interception, event interception, property introduction, event introduction, method introduction, interface introduction, handlers (aka advises in AspectJ), selectors (aka pointcuts in AspectJ). No heavy workaround, like CompoundAspect in PostSharp 1.5, will be necessary to implement a pattern like NotifyPropertyChanged. A dozen of clean lines of code will do the job. I will blog about this very soon.

Developer's Productivity

As teams start using aspects in large projects, it is sometimes difficult to answer two questions:

  • Which aspects are being applied to the method I am now looking at?
  • Conversely, which methods is a given aspect applied to?

With the new Visual Studio add-in, you won't even have to click to have the answers. Would a code element be enhanced by an aspect, it will be lightly underlined. The tooltip text: the list of aspects with hyperlinks.

The objective is simple: stop experimenting with aspects, start being productive with them. And get support from the IDE.

Runtime Optimization

Last but not least, PostSharp 2.0 was designed to emit optimized instructions so that the overhead of aspects, with respect to hand-written code, is as small as possible. Generally, extensibility is achieved at the cost of performance. Here, not. And, believe me, it was not easy to program it. But I did, and it works wonderfully.

What's not there?

Some say that the first commercial version of a product should deliver the smallest possible set of features that still make it interesting to early adopters to buy. PostSharp 2.0 is clearly beyond this line. However, there are things we could have improved but did not fit in the 2.0 schedule: build performance is the principal. We did already big efforts in PostSharp 1.5, but 2.0 will not perform better. We have ideas how to improve it and will work on it in future releases. If you are experiencing performance problems with PostSharp 1.5, be sure that it is installed on your computer using the installer (not the zip package) so that native images are used. PostSharp startup time will be significantly reduced (and PostSharp 1.5/2.0 starts as many times as you have projects in the solution).

What's taken over from PostSharp 1.5

There are basically two components in PostSharp 1.5: PostSharp.Core and PostSharp.Laos.Weaver. PostSharp.Core is kept without significant change (so, if you are just using this components, upgrading to 2.0 will be minor work). However, PostSharp.Laos.Weaver is dropped and replaced by the new aspect framework I talked about before.

PostSharp.Laos itself (the layer most people use directly) will have partial source-level compatibility to version 1.5. Actually, PostSharp.Laos will run emulation on the top of the new aspect framework. Most unit tests done for PostSharp Laos 1.5 still run in version 2.0 in emulation mode, but not all. The emulation assembly is fully annotated by [Obsolete] custom attributes to help you migrating to the new framework.

Sure that it will hurt some people. But we had to do it. The objective of PostSharp Laos was to be a quick win in Pareto meaning: 20% of investment on the top of PostSharp Core, covering 80% of use cases (at least these perceived at design time). The new framework was much more expensive and will cover more use cases. But PostSharp Laos, especially the backend PostSharp.Laos.Weaver, was never engineered to be really extensible. So, yes, we fully break compatibility of PostSharp.Laos.Weaver, but it was the price to have compatibility with the new framework.

Summary

I have chatted a lot about the vision behind PostSharp 2.0. I wrote a lot of words because I wanted to express the context and the challenges we are trying to solve.

To summarize, the design objectives of PostSharp 2.0 are:

  • To reliably support multi-vendor solutions, implying:
  • o Strict binary backward compatibility,
  • o Aspect dependency checking;
  • To implement a large vision of aspect-oriented programming (many features);
  • To improve productivity of developers working with aspects (IDE support);
  • To improve runtime performance.

Next week I will start to blog technically about new features.

Your Responsibility

I opened this post by reminding the greater responsibility coming from the position of leading aspect framework. As a closing remark, I wanted to share a part of this responsibility with you: as an early adopter of aspect-oriented technologies, your feedback will be vital. You know how communication is like: people will blog about it, say it's great (it is), and so on. I will do the same because I need to sell. But don't forget we are first engineers and not marketers.

I want you to break the product. Find flaws. Find the weak element. Where will the design break, when it will break? Compare the features to your cases. Is there a case we could solve with a small design modification? We will maybe not solve your use case in this release, but make sure the design allows us to address the case in a future release. Nobody else than you, knowledgeable of your particular business, can provide this feedback.

Thank you.

Happy PostSharping!

-gael