I will be present as a speaker at PRIO.Conference 2009 in Munich, Germany, 28th of October 2009. My session is at 17h30. It will be the first presentation of PostSharp 2.0 ever and I will show some concrete aspects useful in GUI applications.
I will be in Munich from the 27th evening to 29th afternoon, so feel free to take a date if you want to meet me there.
Many thanks to Ralf Westphal for inviting me!
See you there!
-gael
In my
previous post, I have given a quick overview of some new features of the
aspect weaver.
Equally important to features: runtime performance.
PostSharp 1.5 already did a great job compared to other aspect frameworks.
However, this could still be greatly improved. And this had been done in
PostSharp 2.0.
Take, for instance, a rather simple aspect: a performance counter. Say we
want to increase a counter every time a method is executed. The easiest and most
efficient way with PostSharp 1.5 is to create an aspect of type
OnMethodBoundaryAspect and to implement the OnEntry:
[Serializable]
public sealed class MethodInvocationCounterAttribute : OnMethodBoundaryAspect
{
[NonSerialized]
private PerformanceCounter performanceCounter;
public MethodInvocationCounterAttribute(string category, string name)
{
this.Category = category;
this.Name = name;
}
public string Category { get; private set; }
public string Name { get; private set; }
public override void RuntimeInitialize(System.Reflection.MethodBase method)
{
this.performanceCounter = new PerformanceCounter(this.Category,
this.Name, false);
}
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
this.performanceCounter.Increment();
}
}
Now let's apply this aspect on an empty method (and forbid inlining), and put
it on the test bench (here on my AMD Phenom II X4 940 3.00 GHz):
| Implementation |
CPU Time (ns) |
Overhead (ns) |
| Manual implementation |
26 |
0 |
| PostSharp 1.5 |
108 |
82 |
As you can see, in PostSharp 1.5, the overhead of the using an aspect,
compared to hand coding, is 108 - 26 = 82 ns (remember, a nanosecond is a
billionth of a second). What's the problem? The aspect overhead may is
more than 3
times the aspect effect itself! If the aspect has to be invoked thousands of
times per second, its cost can surely not be ignored.
Now look at the benchmark with PostSharp 2.0:
| Implementation |
CPU Time (ns) |
Overhead (ns) |
| Manual implementation |
26 |
0 |
| PostSharp 2.0 |
29 |
3 |
This time, it's much better. For this specific aspect, PostSharp 2.0 is
more than 25 times faster at runtime than PostSharp 1.5! Most importantly, the
overhead of the aspect is now only a small fraction of the cost of the effect
itself. So it now makes perfectly sense to use an aspect for lightweight
instrumentation.
How does PostSharp 2.0 achieves this performance gain? In short, by being
smarter about the code it generates. PostSharp 1.5 did not look into the code of
your aspects, it had to generate code for any offered feature, even if your
aspect did not use them. Therefore, PostSharp 1.5 generated a lot of useless
instructions. This is clear if we looked at the output assembly using Reflector:

As you can see, there are instructions to pass the parameters of the method
to the aspect, even if the aspect never uses them. Handlers OnSuccess,
OnException and OnExit are invoked, even if the aspect does not
implement them. That's bad overhead: it does not translate into anything
useful.
PostSharp 2.0 is way smarter: it analyzes the code of your aspect, figures
out which feature you actually use, and generate instructions only for them. Watch the difference:

No wonder it's faster. Since the aspect does not even use the eventArgs
object, why should we pass it? PostSharp 2.0 is smarter than you could think: it
also looks at which member of MethodExecutionEventArgs you are using. So
if you read the Instance property and not the Arguments property,
you will get Instance, not Arguments.
Sure, there is a catch in this benchmark: I have intentionally chosen an
example where the improvement is dramatic. But, from today, you know that you can
achieve amazing performance with OnMethodBoundaryAspect, and that it's up
to you to design an aspect that is really lightweight at runtime. The learning
curve of PostSharp has always been pay-as-you-consume. Now runtime performance
is also pay-as-you-consume.
What with other aspects? Take
OnMethodInvocationAspect. It has been reimplemented from scratch, is now
named MethodInterceptionAspect, and is
"just" 77% faster in PostSharp 2.0 than in PostSharp 1.5.
PostSharp 2.0 delivers better runtime performance by playing on 3 factors:
- Adaptive Code Generation, as demonstrated above (major benefits in
OnMethodBoundaryAspect, minor benefits elsewhere).
- Use of generic tuples instead of untyped arrays to store arguments (no
boxing-unboxing, no casting).
- Use of binding classes instead of delegates.
- Aggressively optimized design (we do consider a virtual call or a
boxing/unboxing cycle as an expensive operation).
- Cross-aspect optimizations, delivering great benefits when many aspects
are applied to the same method (artifacts used by an aspect can be reused by
next aspects in chain).
Now a last piece of code. What if a 3 ns overhead is still too much for your
case? Look at the following piece of code, it has zero overhead.
[Serializable]
public sealed class MethodInvocationCounter3Attribute : MethodLevelAspect
{
[NonSerialized]
private readonly static PerformanceCounter performanceCounter;
static MethodInvocationCounter3Attribute()
{
if ( !PostSharpEnvironment.IsPostSharpRunning )
{
performanceCounter = new PerformanceCounter("Custom", "NumberOfItems64", false);
}
}
[OnMethodEntryHandler, SelfSelector]
public static void OnEntry(MethodExecutionArgs eventArgs)
{
performanceCounter.Increment();
}
}
The OnEntry handler is a static method. So, when applied on a target
method, it gives the following:

Since the OnEntry handler is inlined by the JIT compiler, this method is
strictly equivalent to invoking performanceCounter.Increment manually
from the instrumented method. Sure, your possibilities are very limited when you
use a static method (you can't access instance fields of the aspect instance, so
the counter name has to be the same for all methods using this aspect). But the
promise holds: you use nothing, you pay nothing. Here, the aspect is free of any
overhead.
Happy PostSharping!
-gael
PS. Kicking ass?
Be seated safely before reading on. This kicks ass.
I have already written enough abstract words in previous posts; let's now
introduce PostSharp 2.0 on a real example: the implementation of
NotifyPropertyChanged, one of the most frequently used patterns for all adepts
of MVC designs.
It's not just about implementing the INotifyPropertyChanged interface; it's
also about modifying every property setter. It's deadly simple and deadly
boring. And gets you more than one step away from the idea you have of aesthetical
code.
Enough words. See the implementation using PostSharp 2.0. There's a lot of
new concepts out there, so let's start easily:
[Serializable]
[IntroduceInterface( typeof(INotifyPropertyChanged))]
public sealed class NotifyPropertyChangedAttribute :
InstanceLevelAspect, INotifyPropertyChanged
{
public void OnPropertyChanged( string propertyName )
{
if ( this.PropertyChanged != null )
{
this.PropertyChanged( this.Instance,
new PropertyChangedEventArgs( propertyName ) );
}
}
[IntroduceMember]
public event PropertyChangedEventHandler PropertyChanged;
[OnLocationSetHandler,
MulticastSelector( Targets = MulticastTargets.Property )]
public void OnPropertySet( LocationInterceptionArgs args )
{
if ( args.Value == args.GetCurrentValue() ) return;
this.OnPropertyChanged( args.Location.PropertyInfo.Name );
}
}
The aspect is used this way:
[NotifyPropertyChanged]
public class TestBaseClass
{
public string PropertyA { get; set; }
}
Some words of explanation.
First, look at introductions: IntroduceInterface tells that the
interface INotifyPropertyChanged must be introduced into the target type.
And where is the interface implemented? Well, by the aspect itself! Note that
PropertyChanged is itself introduced to the target type as a public member
thanks to the IntroduceMember custom attribute (without this attribute,
the interface would be implemented explicitely).
The aspect actually becomes an extension of the class; aspect instances have the
same lifetime as objects of the class to which the aspect is applied... just
because the aspect inherits from InstanceLevelAspect.
Got it? So let's continue to the OnPropertySet method. It is marked by
custom attribute OnLocationSetHandler: it makes this method a handler
that intercepts all calls to the setter of all target properties. And which are
target properties? This is told by custom attribute MulticastSelector:
all properties in this case, but we could filter on name, visibility and all
features you are used to. We could have used the same handler to handle access
to properties (it would have turned the field to a property as a side effect).
Did you get it? You can now catch accesses to properties or fields using the
same aspects. Same semantics, same aspect. Simple, powerful.
Now look at the body of method OnPropertySet and see how easy it is to
read the current value of the property.
The code above works on an isolated class, but a class is rarely isolated,
right? More of the time, it derives from an ancestor and have descendants. What
if the ancestor already implements interface INotifyPropertyChanged? The code
above would trigger a build time error. But we can improve it. What do we want,
by the way? Well, if the class above already implements
INotifyPropertyChanged, it must also have implemented a protected method
OnPropertyChanged(string), and we have to invoke this method. If not, we
define this method ourselves. In both cases, we need invoke this method from all property setters.
Let's turn it into code:
[Serializable]
[IntroduceInterface( typeof(INotifyPropertyChanged),
OverrideAction = InterfaceOverrideAction.Ignore )]
[MulticastAttributeUsage( MulticastTargets.Class,
Inheritance = MulticastInheritance.Strict )]
public sealed class NotifyPropertyChangedAttribute :
InstanceLevelAspect, INotifyPropertyChanged
{
[ImportMember( "OnPropertyChanged", IsRequired = false )]
public Action<string> BaseOnPropertyChanged;
[IntroduceMember( Visibility = Visibility.Family,
IsVirtual = true,
OverrideAction = MemberOverrideAction.Ignore )]
public void OnPropertyChanged( string propertyName )
{
if ( this.PropertyChanged != null )
{
this.PropertyChanged( this.Instance,
new PropertyChangedEventArgs( propertyName ) );
}
}
[IntroduceMember( OverrideAction = MemberOverrideAction.Ignore )]
public event PropertyChangedEventHandler PropertyChanged;
[OnLocationSetHandler,
MulticastSelector( Targets = MulticastTargets.Property )]
public void OnPropertySet( LocationInterceptionArgs args )
{
if ( args.Value == args.GetCurrentValue() ) return;
if ( this.BaseOnPropertyChanged != null )
{
this.BaseOnPropertyChanged( args.Location.PropertyInfo.Name );
}
else
{
this.OnPropertyChanged( args.Location.PropertyInfo.Name );
}
}
}
This time, the code is complete. No pedagogical simplification. Look at
custom attributes IntroduceInterface and IntroduceMember: I have
added an OverrideAction; it tells that interface and member introductions
will be silently ignored if already implemented above.
Now look at field BasePropertyChanged: its type is Action<string>
(a delegate with signature (string):void) and is annotated with custom
attribute ImportMember. At runtime, this field with be bound to method
OnPropertyChanged of the base type. If there is no such method in the base
type, the field will simply be null. So, in method OnPropertySet, we can
now choose: if there was already a method OnPropertyChanged, we invoke
the existing one. Otherwise, we invoke the one we are introducing.
Thanks to ImportMember, we know how to extend a class that already
implement the pattern. But how to make our own implementation extensible by
derived classes? We have to introduce the method OnPropertyChanged and
make it virtual. It's done, again, by custom attribute IntroduceMember.
That's all. You can now use the code on class hierarchies, like here:
[NotifyPropertyChanged]
public class TestBaseClass
{
public string PropertyA { get; set; }
}
public class TestDerivedClass : TestBaseClass
{
public int PropertyB { get; set; }
}
class Program
{
static void Main(string[] args)
{
TestDerivedClass c = new TestDerivedClass();
Post.Cast<TestDerivedClass, INotifyPropertyChanged>( c ).PropertyChanged += OnPropertyChanged;
c.PropertyA = "Hello";
c.PropertyB = 5;
}
private static void OnPropertyChanged( object sender, PropertyChangedEventArgs e )
{
Console.WriteLine("Property changed: {0}", e.PropertyName);
}
}
With PostSharp 1.5, you could do implement easy aspects easily. With
PostSharp 2.0, you can implement more complex design patterns, and it's
still easy.
Happy PostSharping!
-gael
P.S. Kicking?
Yesterday, C# MVP
Job Skeet blogged about a
way to add generic constraints for enums and delegates. He noticed that,
while the C# compiler forbids such constructions, it is perfectly possibly in MSIL.
And he is fully right with this.
Jon uses a post-build step to add modify generic constraints.
His process: ILDASM, then find-and-replace, then ILASM. That’s possible because
the requirement is pretty easy.
But here he challenged me:
I've looked at
PostSharp and
CCI; both look
way more complicated than the above.
Sure, PostSharp
would be more complex, but Jon’s ILASM-based solution works only in best cases.
There are plenty of things that you have to keep in mind while building a post-build
step that modifies MSIL. For instance, how will ILASM find referenced assemblies?
What with signed assemblies? Sure,
you can find a solution to everything – after all, PostSharp uses ILASM as a back-end
(contrarily to rumors, it does not use
ILDASM). But, believe me, addressing these side issues will prove more difficult
than the core job itself.
And anyway, why
would it be so complex to implement these rather simple requirements using PostSharp?
PostSharp is designed so that easy jobs get easily done.
I took the challenge
and implemented an add-in adding arbitrary constraints to generic parameters. I
measured time. It took me 30 minutes. NDepend counts 12 lines of code.
It’s based on
custom attributes. PostSharp loves custom attributes. I defined a custom attribute
AddGenericConstraintAttribute
that can be applied to generic parameters. Here is how it’s used:
public static class EnumHelper
{
public static T[] GetValues<[AddGenericConstraint( typeof(Enum) )] T>()
where T : struct
{
return (T[]) Enum.GetValues( typeof(T) );
}
}
The project can
be downloaded from
http://postsharp-user-samples.googlecode.com/files/AddGenericConstraint.zip.
In order to use the plug-in, follow the
documentation.
Here are the
principal steps I followed to create this plug-in:
1.
Create
a new solution AddGenericConstraint.sln.
2.
Create
a new class library project AddGenericConstraint.csproj. This project will be the
public interface of the plug-in.
3.
Create
the class AddGenericConstraintAttribute.cs:
[AttributeUsage( AttributeTargets.GenericParameter )]
public sealed class AddGenericConstraintAttribute : Attribute
{
public AddGenericConstraintAttribute( Type type )
{
}
}
4.
Create
a new class library project AddGenericConstraint.Impl.csproj. This will contain
the plug-in implementation.
5.
Add
references to PostSharp.Public.dll, PostSharp.Core.dll, AddGenericConstraint.csproj.
6.
Create
a class AddGenericConstraintTask. This is the real implementation class. This is
the hard point.
public class AddGenericConstraintTask : Task
{
public override bool Execute()
{
// Get the type AddGenericConstraintAttribute.
ITypeSignature addGenericConstraintAttributeType =
this.Project.Module.FindType(
typeof(AddGenericConstraintAttribute),
BindingOptions.OnlyDefinition | BindingOptions.DontThrowException );
if ( addGenericConstraintAttributeType == null )
{
// The type is not referenced in the current module. There cannot be a custom attribute
// of this type, so we are done.
return true;
}
// Enumerate custom attributes of type AddGenericConstraintAttribute.
AnnotationRepositoryTask annotationRepository =
AnnotationRepositoryTask.GetTask( this.Project );
IEnumerator customAttributesEnumerator =
annotationRepository.GetAnnotationsOfType(
addGenericConstraintAttributeType.GetTypeDefinition(), false );
while ( customAttributesEnumerator.MoveNext() )
{
// Get the target of the custom attribute.
GenericParameterDeclaration target = (GenericParameterDeclaration)
customAttributesEnumerator.Current.TargetElement;
// Get the value of the parameter of the custom attribute constructor.
ITypeSignature constraintType = (ITypeSignature)
customAttributesEnumerator.Current.Value.
ConstructorArguments[0].Value.Value;
// Add a generic constraint.
target.Constraints.Add( constraintType );
// Remove the custom attribute.
((CustomAttributeDeclaration) customAttributesEnumerator.Current).Remove();
}
return base.Execute();
}
}
7.
Add
an XML file AddGenericConstraint.psplugin to the project. This file will describe
your plug-in. In file properties, specify “Copy to Output Directory: Copy Always”.
<?xml version="1.0" encoding="utf-8" ?>
<PlugIn xmlns="http://schemas.postsharp.org/1.0/configuration">
<TaskType Name="AddGenericConstraint" Implementation="AddGenericConstraint.Impl.AddGenericConstraintTask, AddGenericConstraint.Impl" Phase="Transform">
<Dependency TaskType="Remove" Position="After"/>
<Dependency TaskType="AnnotationRepository"/>
</TaskType>
</PlugIn>
8.
Go
back to project AddGenericConstraint. Add a reference to PostSharp.Public.dll.
Add the following on the top of the
class AddGenericConstraintAttribute to bind the custom attribute to its implementation:
[RequirePostSharp( "AddGenericConstraint", "AddGenericConstraint" )]
9.
Create
a test project. Add references to PostSharp.Public.dll and AddGenericConstraint.csproj.
In project properties, add directory “..AddGenericConstraint.ImplinDebug” to
reference paths.
10.
You
are done.
What’s the catch?
Maybe that, if you don’t know PostSharp Core and MSIL, it will take you days to
come with the 12 lines of code that form the implementation. But when you got the
knowledge, you are incredibly productive. And all the issues caused by the integration
in the build process are solved for you. Believe me, after 5 years of existence,
there is a huge knowledge behind PostSharp
integration.
Happy PostSharping!
-gael
PS. It took me
longer to write this blog than the implementation itself.
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
Although PostSharp and aspect-oriented programming are still considered new by most of the .NET community, it's already been five years this month since I started the project. It's a good opportunity to look back, explain how the project started, what it has become, and where it goes.
Reasons to Start
PostSharp started at the end of summer 2004 when a colleague drew my attention to aspect-oriented programming. AspectJ was already popular in the Java ecosystem; there were a multitude of small AOP projects for .NET, but all of them were in bad shape and did not look attractive to developers. As it turned out, all of these projects died after they missed the upgrade to .NET 2.0.
My first attempt to implement AOP was to use System.Reflection.Emit, but I quickly figured out that I needed a better tool for the job. The tool would allow for any edition of an MSIL assembly. There was simply no good tool available, so I took the decision to start one. Coincidentally, Jean-Baptiste Evain took the same decision roughly at the same time and developed Cecil, now a part of the Mono project. Because a coincidence never comes alone, Jean-Baptiste is also a French speaker and he lives in Lyon, a city to many respects similar to Prague, in the surroundings of which I've lived last 8 years. There are, however, big differences in the approach and the set of features offered by these products (PostSharp being more a framework, Cecil a library).
Of course, finding a good problem to solve is not a sufficient reason to start solving it. As always, psychological reasons are of uppermost important.
In summer 2004, I was just realizing that I my career in Czech Republic was stuck in a dead end. I was realizing that my employer was a body shop and got no chance to leave it in short time. They sold me to a telecom operator called Oskar (now Vodafone); I was now coding business processes in PL/SQL and was discovering, at own expenses, what it means to work in a corporate environment. I eventually staid 3 years in this company and never got successful.
So, while working in Oskar, my rationale for PostSharp was to get professional recognition with the intention that I could escape from the traps of being a commodity software developer. I had another reason for PostSharp, although not rational: I just needed some real food for my brains; I needed a project of my own and an existence outside the constant pressure of 7 levels of hierarchy.
With respect to these objectives, the PostSharp project was certainly a right decision and delivered all expectations.
While working at Vodafone, I often wondered how many people were in my situation. How many talents are crushed by hierarchy and bureaucracy? How much does it cost in terms of productivity? How much does it cost in terms of missed opportunity of happiness? I believe many of you live the same difficulties.
There was, however, another reason for starting PostSharp, an unofficial one: in summer 2004, we just got our first baby and my wife started to go to bed every night at 9PM. So what can you do when you are a real programmer and get bored in the evening? To program, right? You maybe got the real reason of PostSharp. I worked on the project every night from 9PM to 11PM.
Times have changed since this summer; we now have 3 kids and no time left in the evening!
Freelancing
It took me two years, at this pace, to publish the first alpha release of PostSharp, including PostSharp Core and PostSharp Laos. In fall 2006, people started to show interest for PostSharp. The company X-tensive.com started to work on DataObjects.NET 4.0 and decided to use PostSharp. Starcounter decided to use PostSharp in their product and sponsored some development. I understood there was some commercial interest and it gave me courage to continue.
In fall 2006, we already all knew at Vodafone that our jobs would be outsourced to IBM. As it turned out (we did not know it at this time because of their white lies), most jobs would be offshored to India. But instead of being transferred to IBM as most of my colleagues did, I preferred to simply leave and to use the firing indemnity to start as a freelancer.
So at the end of spring 2007, I started as a freelancer. My objective: to work part time on PostSharp and part time for customers.
From this moment, things began to accelerate a bit.
In March 2007, I released the first feature-complete version of PostSharp. In August 2007, I presented the project to the European Conference on Object Oriented Programming (ECOOP). I published the first candidate of PostSharp 1.0 in September 2007 and started to work on PostSharp 1.5.
From November 2007 to January 2008, I was lucky enough to work with Roman Stanek on his new start-up Good Data, which greatly helped me to better understand the business of software. Then, from March 2009, I have worked part time with Starcounter; I am helping them building a new object-oriented database server hosing the CLR.
In December 2007, I was interviewed on .NET Rocks online radio. Then, in 2008, I virtually toured Europe and presented the project in Poland, Germany, Sweden, Netherlands, and Czech Republic. PostSharp 1.0 RTM was announced in September 2008 during the conference in Prague.
In fall 2008 I started to realize that the current business model did not work: a part time was not enough to maintain and promote the project; releases were too slow to come to market. I realized I needed to work full time on the project, which also meant that the project had to make money. So, by November 2008, I decided to turn the project commercial in two phases. During the first phase, the project would still be open source but commercial licenses would be available, basically, for volunteers. It proved to be a complete failure. During the second phase, the project would be only commercial. This phase is to come this fall.
PostSharp 2.0
So by January 2009 I started thinking about PostSharp 2.0. I decided that this version would have a Visual Studio add-in. I contacted Pawel Hofman, the author of TytanNET, and he accepted to help me with this work. The add-in was fully functional in June 2009. In parallel, I started to work on a fully new version of the aspect framework, in replacement of PostSharp Laos. An aspect framework that would last 5 years with backward compatibility. At the time of writing, the job is almost done and, as far as I can judge my own work, the result is great. PostSharp 2.0 will proudly stand in comparison with AspectJ (I did not say PostSharp will offer all the features of AspectJ). I will blog later about technical features of PostSharp 2.0.
So you heard it officially: PostSharp 2.0 will be commercial. There will be a community edition, free as beer, with a limited set of features. Source code will be available under a blue print license. There will be give-away copies for open-source projects and opinion leaders. And there will be a real strategy for ISVs who want to integrate PostSharp into their product. So most of you will (hopefully) pay for the product; it's just fair and I think most of you guys expect it and think the same (this was clearly the dominant opinion in the February's Community Survey).
Good news for all users is that there will be a real company behind the product. So far, I am running the project as a physical person (freelancer). There will now be a real company, a real business plan, real investors who risk their own real money, real attorneys and so really on.
Here's what you can expect next months:
It will still take many months before the company is ready to function as a company. But before the company is ready, I will start releasing previews under an evaluation license. You can expect a first preview still this month. This preview cycle will help stabilizing the product and get feedback on the new architecture. Remember that this architecture is designed to be backward compatible during 5 years, so your feedback will be crucial. Commercial licenses some time later, as soon as we will be ready both legally, commercially and technically.
Summary
During last 5 years, PostSharp has grown from a pet project to the leading aspect framework for .NET (many popular application frameworks can do some AOP, but cannot be called aspect frameworks). PostSharp has a large user base composed principally of professionals who rely on the product for critical applications. This month is a turn for PostSharp: we are in the process of creating a company to incorporate the product; we are to release first previews of PostSharp 2.0 with some breaking innovations for professional users.
Happy PostSharping!
-gael