Wednesday, July 19, 2006

Applying PicoContainer.NET with Presentation Patterns - Part I

There is a couple favourite presentation-layer design patterns that I have been consistently using to build .NET applications. In particular, they are Presentation Model and Model-View-Presenter. Both are extremely handy when it comes to making the code-behind of your View more testable by delegating its responsibilities to another layer of code. From that layer, you can start chipping in various flavors of dependency injections and stubs and mocks to start going all-out unit testing assault to your code.

In many cases, on a per View basis (like a page or user control), there is a Presentation Model class, or a Presenter class, sitting behind it ready to receive a call from its corresponding View, then execute the behavior called upon.

PicoContainer.NET (Pico from here on) encourages more decoupled object-oriented class design by helping you to manage your classes' dependencies. As a quick example, suppose you have a class iPod (you know what it is, right?) and a class Battery. Obviously iPod depends on a battery. However, the iPod class at construction time creates its own Battery instance to use and cannot take any other battery types (to the dismay of iPod users). Now your iPod stopped working and you have to figure out why. If you need to test your iPod, you have to be extremely creative to figure out where the problem is related to its battery or not somehow. How do you know if the problem lies in the iPod, or its battery? This is why good code minimize dependencies. Suppose, however, your iPod receives a Battery instance through its constructor. Then in the unit tests of your iPod class, you can then mock/stub the battery out and start exclusively interrogating and verifying the behaviors of your iPod class. iPod now can be injected with a mock Battery instance, and hence your iPod class is more testable, and its tests are more "unit" and not touching other parts of your code. You can then start writing more automated unit tests that run in milliseconds easily.

The question now is who then is responsible for passing a Battery instance into iPod. That's where Pico shines. If, as mentioned, your iPod has such a constructor that takes in the Battery dependency, using Pico as a container, you register your iPod and Battery class into the container, when you ask the container for an iPod instance, the Battery instance (since it is also registered) will be instantiated automagically and you can now start using your iPod object, without having to hard-code your iPod class to instantiate its own Battery.

Because Pico is such a great tool, I have used it in various .NET projects of mine. Since Pico uses a registration scheme, whatever you put into a Pico container you get its dependency-wiring functionality for free, many things tend to be put into it. Afterall, Pico encourages good design, right? As a result, Views, Presentation Models, Presenters, etc., are all registered into Pico container. The Pico container is set up at public static void Main() time, and when you run Application.Start(form) you pass it into your form object. From there all of your Views can programmatically ask for its dependencies. Life is good.

Why are Views being put into the container? Because every View needs a delegating Presentation Model or Presenter to handle its behavior, meaning, every View "depends" on a Presentation Model or Presenter. As a result, they all get registered into Pico in order for the form to get navigate the user to the correct View.

Life is good - until stuff happens. Since constructor injection is the preferred way to inject dependencies, if your View "depends" on something, then your View would need a constructor passing in its dependencies before Pico can start wiring dependencies on your behalf. Every .NET programmer knows that, every View (regardless you use a Form or User Control) has a default parameter-less constructor that has a default line InitializeComponent(). This is because the Visual Studio .NET IDE uses this constructor to support WYSIWYG at design time. Tampering with or getting rid of this constructor and/or the InitializeComponent() method call will get your IDE trouble in supporting editing your View at design time.

A second problem that would arise is that, consider I have a User Control. It is also a View, albeit being used and instantiated by its parent View (maybe another User Control). Since this child user control instance is created by the auto-generated code from the parent Views InitializeComponent() method call, you cannot modify this child user control's default constructor to take in its "dependency" Presentation Model/Presenter, and then hope that its parent Form can somehow inject the child control's dependencies inside its InitializeComponent() method. Even if you can modify these auto-generated code, your IDE design-time support is now in jeapardy. Because of this problem, some Pico programmers would buck the constructor injection coding consistency, pass in the child user control's dependencies into the parent View's constructor, and start using setter injection to inject the child user control's dependencies, after the parent Form's InitializeComponents() method call. That way at least you can leave the child user control's default constructor alone and continue to use VS's strong IDE support, while managing your child control's dependencies.

What to do? Now comes Part II - My attempt to get the best sides of all worlds: Use Pico to manage dependencies; and have VS.NET IDE WYSIWYG support.

No comments: