Thursday, January 31, 2008

The Model, View, and (Virtual) Presenter Pattern



One of the greatest weaknesses of the
MVP/MVC pattern is that although the the model is completely separated from the view (and vice-versa), the view in the MVP pattern has to have a concrete dependency on its corresponding Presenter in order to function. At first, there doesn't seem to be a way to completely isolate all three components of the MVP pattern from each other, given that the view has to have a reference to a concrete presenter. The presenter, on the other hand, knows nothing about the concrete view, other than the IView interface that is implemented by the view itself; it's a one way dependency, and yet, something just doesn't 'feel' right here...

The Epiphany


...and then that's when the questions started to hit me:
Does the presenter even have to be a concrete presenter at all? Is it possible to replace a concrete presenter with an interface type, and what would that interface look like? Are all presenters the same, or do they just all represent some sort of abstract concept that can't be centralized into a single common class?

My proposal for changing the MVP pattern is this: What if we convert the concept of the presenter from a concrete class to an abstract metaclass? If we change the presenter from a concrete class to an abstract implementation of a concept, we can effectively eliminate the dependency between all three parts of the MVP triad. It might sound complex, but the implementation is actually quite simple. In this variant of the MVP pattern, we can completely eliminate the view's dependency on a concrete presenter by converting the concrete presenter dependency into a collection of interfaces that the view requires in order to function.

A Quixotic Attempt


A naive approach would be to try to find a common interface to be implemented by presenters, but this poses a problem--no two presenters will ever be exactly alike. A presenter that will handle a list view won't always have the same interface as a presenter that handles a date field. In addition, there might be presenters which might hold some business or validation logic that other presenters might not necessarily share. In other words, we're dealing with a situation where each presenter interface allmust be heterogenous for each view type, and that makes it difficult to group all of the presenters into a single interface that could be used by each view type.

Dead End?

At first, it might seem like we have no choice but to make each presenter concrete and customize each one of them to fit their corresponding views--but what if we refactored each one of these concrete presenters into multiple interface dependencies for each view? If you think about it, a concrete presenter is nothing but a collection of different responsibilities assigned to a concrete interface. For example, a DatePresenter class might have a few methods that check if the date value presented in the view is valid. The same DatePresenter class also might have methods which can persist the date value to the database. The crux of the concrete presenter in the MVP pattern is that the date view relies on this same DatePresenter to control its behavior. There's a one-way separation between the view and the presenter, and there has to be a way to completely isolate the presenter from the view itself.

An Unnecessary Coupling

A view (for the most part) doesn't need a reference to a concrete presenter class as much as it needs a reference to the interfaces and responsibilities that each one of those interfaces represent. In fact, if I were to refactor a concrete presenter, extract each one of its interfaces, and have each one of those interfaces represent a responsibility that the target view requires, it almost seems like I've converted the concrete presenter into a de facto service container.

Each presenter responsibility corresponds to a service, and each service corresponds to an interface type. Since no two presenters are alike, one could even say that each presenter has a list of services that it offers to each view. So for me, the next logical question is this: If concrete presenters are nothing but de facto service containers, why not use a real service container (aka IoC container) and ditch the concrete dependency altogether?

If a concrete presenter is actually nothing but a degenerate IoC container in disguise, then I can take each one of the view types and replace their concrete presenter dependencies with a single dependency--a dependency on real IoC container by itself. What makes this interesting is that in this variant of the MVP pattern, the 'P' in the MVP pattern no longer exists as a concrete class. The view's concrete dependency on the presenter has been supplanted by interface dependencies supplied by an IoC container. Using this scheme, the view knows nothing about the actual presenter concrete class, and the presenter knows nothing about the concrete view class. As an added bonus, we can even separate the presenter from the concrete model by having the presenter rely on interfaces supplied by the model, and vice versa. The best part about all this is that (aside from the interface dependencies) all three parts of the MVP triad are completely isolated from one another. The only dependency that all three parts of the MV(P) pattern share is the IoC container itself, and since most IoC containers are easily configurable by design (namely LinFu), this dynamically gives us complete control over all the dependencies of a given application...

Note: So far, all of this is just theory, and I have to write it down somewhere before I forget it. I think this pattern can help quite a lot of people, and hopefully I can test it soon.

Tuesday, January 29, 2008

LinFu.AOP Released!

After two long weeks of pounding away at the keyboard, I'm finally finished with the article for LinFu.AOP, and I'm proud to say that it's finally been released to the SVN repository for general use!

So if you haven't downloaded a copy of LinFu.AOP yet, feel free to update your SVN copy to the latest revision as soon as possible--trust me, you don't want to miss this one! :)

Now, if only CP can publish my article fast enough...

Friday, January 18, 2008

Writer's Block, or Write this Block?

I've been incredibly busy over the past few weeks so I haven't had time to update my blog until now. I've pretty much temporarily frozen any further development with LinFu (aside from bug fixes) until I can get the Part VI article out the door and released to CodeProject. I don't know why, but lately I've caught a really bad case of writer's block. It seems like there's so many topics that I need to cover for Part VI, but I can't seem to flesh out all the details without reading through the current draft and finding glaring omissions in the documentation itself. Call me an obsessive perfectionist, but I won't release any article unless I know that it meets my standards.

I can't really quantify it, but my intuition is telling me something wrong here--and I won't rest until I can finally get this article fixed.

Saturday, January 5, 2008

A Familiar Story, Told by LinFu.AOP

Here's a simple story that shows what one can do with LinFu.AOP. Note the code listing below:

public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public void Speak()
{
Console.WriteLine("Hello, World!");
}
}

public class Demon
{
public string Name
{
get { return "Captain Howdy"; }
set { throw new InvalidOperationException("Are you crazy??"); }
}
public int Age
{
get { return 999999; }
set { }
}
public void Possess(Person person)
{
DynamicObject dynamic = new DynamicObject(this);
dynamic.Attach(person);
}
public void Deposses(Person person)
{
MakeHeadSpin();
VomitGreenStuff();
throw new InvalidOperationException("Fat chance, buddy!");
}
public void MakeHeadSpin()
{
// ...
}
public void VomitGreenStuff()
{
// ...
}
public void Speak()
{
Console.WriteLine("This girl is mine!");
}
}
class Program
{
static void Main(string[] args)
{
// There once was a nice little girl...
Person girl = new Person() { Name = "Linda Blair", Age = 6 };

// Who spoke in a soft voice..
girl.Speak();

// Until one day, she played with some crazy oija board named 'LinFu.AOP', and
// then everything changed...
Demon demon = new Demon();
demon.Possess(girl);
IModifiableType modified = girl;
girl.IsInterceptionEnabled = true;

// Then some devoted priest came along and spoke with the girl, and she said:
girl.Speak();

// He took pity on the girl, and tried to free her from the demon.
demon.Deposses(girl);

// The demon resisted, but the priest was smart, and in the end,
// he subdued the demon.
girl.IsInterceptionEnabled = false;


// ..the end
return;
}
}

The Devil in the Details

Now, if you look at that code listing above, you'll notice that the Person class has no idea that it's being intercepted at all. In fact, poor little Linda doesn't know the trouble she's getting into. The Demon class was able to possess Person types because LinFu.AOP modified the Person class to allow itself to be dynamically intercepted at runtime, all without the knowledge of the said victim.

What makes this interesting, however, is that interception can be easily turned on or off depending on the value of the IsInterceptionEnabled property. In fact, if interception is turned off, the Person class will behave just like any other normal person without any performance penalties that are typically incurred by pass-through interception. If interception is turned on, of course, you'll be bound to have some performance overhead incurred, but the added flexibility bonus is staggering. With the slight decrease in performance, you can effectively take over the implementation of the entire class at runtime, and you can even customize it on a per-instance basis.

Think about it. :)

LinFu AOP, Reinvented

After four days of coding and refactoring, I've done it! I've managed to rewrite the original version of LinFu.AOP to address all of the issues that I mentioned in previous posts, and now I only need to write the MSBuild task and the command-line weaver before I can go ahead and start working on the CP article. I know that LinFu.AOP has been vaporware as of late, but I can guarantee you that this is definitely worth the wait.

Aside from the features that I mentioned earlier in this blog, LinFu.AOP will add some interesting features to the LinFu Framework, such as:

Even simpler Simple.IOC integration

With LinFu.AOP, you no longer have to even reference Simple.IOC.dll in your application to use the container. For example, instantiating an IDbConnection type from a SimpleContainer instance will be easy as:

IDbConnection myConnection = New.Instance;

...that's it! Behind the scenes, LinFu.AOP will actually intercept the call made to the following class:

public class New
{
public static T Instance
{
get { throw new NotImplementedException(); }
}
}

Now, believe it or not, the code listing above is the actual implementation of the New class. What I'm actually doing is using LinFu.AOP to redirect the request for an IDbConnection instance to an appropriate factory method (in this case, the Simple.IOC container). What makes this even more interesting is that it employs the same type of XCOPY-style configuration that you would expect from LinFu; it means that if you wanted to inject any more dependencies into the container, all you have to do is drop the new dependencies into the directories, and the container will rebuild itself and that dependency will be available in the next New.Instance call!

LinFu.DynamicProxy 'Submersion'

One of LinFu.DynamicProxy's weaknesses is that its interceptor instances can only be bound to an unsealed type with all of its public methods marked virtual. With LinFu.AOP, that limitation no longer applies.

LinFu.AOP allows LinFu.DynamicProxy interceptors to intercept methods and properties on type instances without even using the proxy generator itself. This means that when LinFu.AOP intercepts a method call done against a target type, there is no intermediate proxy doing the interception. LinFu.AOP rewrites the IL in your method body and redirects it to your interceptor, all at runtime. You can even reuse the old method implementation as if you were still using DynamicProxy.

One could even say that the inteceptor has 'submerged' itself into the type implementation because the interceptor can still intercept any method on any given type as if it were still attached to the proxy--however, what makes it 'submerged' is the fact that you're actually using the true object instance itself!

To take this concept even further, LinFu.AOP supports two levels of method interception: Class-Based, and Instance-Based.

This means that you can either intercept a particular method across all instances of a given type, OR you can actually customize the method replacement (or interceptor) based on the current instance that you're using. Think about that for a moment...

...and while you're thinking about that, I'm going to go back and polish this thing up. :)

Wednesday, January 2, 2008

On Donuts and Method Interception Styles

To keep the ball rolling, LinFu.AOP2 will support the following styles of method interception:

Donut Interception - This means that when a method is intercepted, its original implementation (a.k.a. its method body) will be left intact, but LinFu.AOP2 will inject additional behavior around the original method body--hence, the donut moniker. This can be useful if you want to inspect the input and the output of a given method without altering its implementation.

Donut Hole Interception - This means that when a method is intercepted, its original implementation is completely discarded and replaced with a different implementation altogether.

To make this interesting, LinFu.AOP allows both styles of interception to overlap each other, all at runtime. That means you can inject code 'around' a method body, and you can even replace that method body with something else altogether. Needless to say, this new framework offers a staggering amount of power not readily available in any .NET language today, and the possibilities with it are truly limitless.

(Meanwhile, all this talk of donuts is making me hungry, so I'm off to breakfast...)

LinFu.AOP2 Specifications and Requirements



In general, LinFu.AOP2 must meet the following requirements:

Pervasive Method Interception - It must intercept both instance and static methods on all types, regardless of whether or not the target types are sealed or unsealed. This also includes non-virtual methods.

Type Initialization - It must intercept constructor calls and allow its users to perform custom initialization steps to each type that is created in memory.

No Proxy Required - It must do all of the above interception operations without using any form of DynamicProxy generator (whether it is LinFu, Castle, or whatnot).

Completely Transparent - The target library should not even be aware of any changes made to it by the AOP library. When I look at the source for the target library, there should be no trace or reference to any of the changes made by the new AOP library. In short, all changes should be completely invisible.

No Attributes Required - This means that it should not force the end-user to use .NET attributes at all to specify where any code should be inserted or injected. I might sound like a purist, but in my opinion, the very act of scattering attributes across your application is crosscutting in itself--and that's exactly what AOP is trying to avoid, and I'll do my best to avoid that as well.

Runtime Injection and Interception - LinFu.AOP2 must allow the end user developer to arbitrarily inject or insert any piece of code into an application, all at runtime, not compile time. This is a huge contrast to PostSharp, which only allows you to inject new method behavior at post-build (compile) time.

Language-Independent - It must be able to be used from nearly any .NET language, regardless of the target language's syntax.

Strong Name Signature Stripping - It *should* be able to strip the strong name signature right off of any signed assembly. Given the controversial nature of this particular topic, this feature is completely optional.

Fortunately, since LinFu.AOP1 met seven out of eight of these requirements (that is, everything but the strong name signature stripping), most of the implementation research has already been completed. The only thing left to do is to refine the implementation, and hopefully, it will be ready for an article release on CodeProject.

I'll post as much design notes as I can on this blog to keep everyone posted. Once I come up with any breakthroughs, I'll post some code on this blog for everyone to peruse.

Tuesday, January 1, 2008

Back to the Drawing Board




Although my working prototype of LinFu.AOP has some stunning features such as pervasive
method interception and transparent code injection, at this point, it doesn't quite yet meet my quality standards for something that I would release to the general public, so I'm going to scrap it and start off from scratch.

Queue LinFu.AOP, take two...