tags:

views:

254

answers:

4

I am battling to understand why a post compiler, like PostSharp, should ever be needed?

My understanding is that it just inserts code where attributed in the original code, so why doesn't the developer just do that code writing themselves?

I expect that someone will say it's easier to write since you can use attributes on methods and then not clutter them up boilerplate code, but that can be done using DI or reflection and a touch of forethought without a post compiler. I know that since I have said reflection, the performance elephant will now enter - but I do not care about the relative performance here, when the absolute performance for most scenarios is trivial (sub millisecond to millisecond).

+3  A: 

AOP (PostSharp) is for attaching code to all sorts of points in your application, from one location, so you don't have to place it there.

You cannot achieve what PostSharp can do with Reflection.

I personally don't see a big use for it, in a production system, as most things can be done in other, better, ways (logging, etc).

You may like to review the other threads on this matter:

Noon Silk
Care to explain further what can you do with PostSharp that you can't do with Reflection?
Robert MacLean
You can't insert a method call for every property setter, for example.
Noon Silk
Yeah, you can use the IDE and type it in rather ;)
Robert MacLean
+5  A: 

Suppose you already have a class which is well-designed, well-tested etc. You want to easily add some timing on some of the methods. Yes, you could use dependency injection, create a decorator class which proxies to the original but with timing for each method - but even that class is going to be a mess of repetition...

... or you can add reflection to the mix and use a dynamic proxy of some description, which lets you write the timing code once, but requires you to get that reflection code just right -which isn't as easy as it might be, especially if generics are involved.

... or you can add an attribute to each method that you want timed, write the timing code once, and apply it as a post-compile step.

I know which seems more elegant to me - and more obvious when reading the code. It can be applied even in situations where DI isn't appropriate (and it really isn't appropriate for every single class in a system) and with no other changes elsewhere.

Jon Skeet
Why not just use a profiler? That's what they are for.
Noon Silk
@silky: Yes, but they're not always appropriate. For example, I wouldn't want one running on production jobs, whereas lightweight timing/logging for carefully selected methods *can* be used in production, so you could get real data from real situations.
Jon Skeet
Timing would just be one example. Think e.g. about logging or security where AOP comes in very handy.
0xA3
Jon: Fair point, as always :)
Noon Silk
Slightly tongue in cheeck question but it sounds like you saying it's for people who are either too lazy to plan properly and get the right requirements upfront or people too lazy to write the code and re-test?
Robert MacLean
@Robert: No, not at all. I don't believe that DI is the best answer to everything, even if it can be *a* solution. I don't use AOP much myself, but I can see its benefits.
Jon Skeet
@Jon, I agree that DI is not the answer for everything, and that is not the point I am trying to make. Say you want logging when a method is entered, you could attribute it (1 line) or type the call to the logging on the first line of the method (1 line). So what is the benefit - except the first route allows a developer to be lazy and say they didn't change anything (which they did), so they don't have to retest?
Robert MacLean
@Robert: You're assuming you *only* want it when it's entered. I agree that's easy. What about when it exits as well - in all cases, including when an exception is thrown. Indicating whether it exited normally or not would be useful too. Now your 1 line for doing it manually has grown significantly - but the attribute solution is still 1 line. As for retesting it - do you test all your diagnostic logging? I know I don't... that seems a waste of time to me.
Jon Skeet
+6  A: 

Let's try to take an architectural point on the issue. Say you are an architect (everyone wants to be an architect ;) ). You need to deliver the architecture to your team: a selected set of libraries, architectural patterns, and design patterns. As a part of your design, you say: "we will implement caching using the following design pattern:

string key = string.Format("[{0}].MyMethod({1},{2})", this, param1, param2 );
T value;
if ( !cache.TryGetValue( key, out value ) )
{
   using ( cache.Lock(key) )
   {
      if ( cache.TryGetValue( key, out value ) )
      {
         // Do the real job here and store the value into variable 'value'.
         cache.Add( key, value );
      }
   }
}

This is a correct way to do tracing. Developers are going to implement this pattern thousands of times, so you write a nice Word document telling how you want the pattern to be implemented. Yeah, a Word document. Do you have a better solution? I'm afraid you don't. Classic code generators won't help. Functional programming (delegates)? It works fairly well for some aspects, but not here: you need to pass method parameters to the pattern. So what's left? Describe the pattern in natural language and trust developers will implement them.

What will happen?

First, some junior developer will look at the code and tell "Hm. Two cache lookups. Kinda useless. One is enough." (that's not a joke -- ask the DNN team about this issue). And your patterns cease to be thread-safe.

As an architect, how do you ensure that the pattern is properly applied? Unit testing? Fair enough, but you will hardly detect threading issues this way. Code review? That's maybe the solution.

Now, what is you decide to change the pattern? For instance, you detect a bug in the cache component and decide to use your own? Are you going to edit thousands of methods? It's not just refactoring: what if the new component has different semantics?

What if you decide that a method is not going to be cached any more? How difficult will it be to remove caching code?

The AOP solution (whatever the framework is) has the following advantages over plain code:

  1. It reduces the number of lines of code.
  2. It reduces the coupling between components, therefore you don't have to change much things when you decide to change the logging component (just update the aspect), therefore it improves the capacity of your source code to cope with new requirements over time.
  3. Because there is less code, the probability of bugs is lower for a given set of features, therefore AOP improves the quality of your code.

So if you put it all together:

Aspects reduce both development costs and maintenance costs of software.

I have a 90 min talk on this topic and you can watch it at http://vimeo.com/2116491.

Again, the architectural advantages of AOP are independent of the framework you choose. The differences between frameworks (also discussed in this video) influence principally the extent to which you can apply AOP to your code, which was not the point of this question.

Gael Fraiteur
+1  A: 

Aspects take away all the copy & paste - code and make adding new features faster.

I hate nothing more than, for example, having to write the same piece of code over and over again. Gael has a very nice example regarding INotifyPropertyChanged on his website (www.postsharp.net).

This is exactly what AOP is for. Forget about the technical details, just implement what you are being asked for.

In the long run, I think we all should say goodbye to the way we are writing software now. It's tedious and plainly stupid to write boilerplate code and iterate manually.

The future belongs to declarative, functional style being held together by an object oriented framework - and the cross cutting concerns being handled by aspects.

I guess the only people who will not get it soon are the guys who are still payed for lines of code.

stormianrootsolver