Hanalei, Hawaii Tuesday, February 09, 2010

200 Page Manual on Inversion of Control, Part 2

I’ve received a ton of email with questions about my IoC post the other day, so I thought I’d take a minute (or 60) and write up a followup. In this post I’ll try to put some pieces together and explain a bit more as to *why* you might want to use DI/IoC and how it won’t turn your application into the Mars Rover.

I’ve received a ton of email with questions about my IoC post the other day, so I thought I’d take a minute (or 60) and write up a followup. In this post I’ll try to put some pieces together and explain a bit more as to *why* you might want to use DI/IoC and how it won’t turn your application into the Mars Rover.
Quick Review
In the last 2 posts I’ve covered 4 “Cool Kid” patterns and tools:
  1. Dependency Injection: wiring a class to take its dependencies via constructor
  2. The Repository Pattern: formalizing your data access into a class with explicit methods (IPostRepository)
  3. Inversion of Control: using a special container to instantiate your objects for you, rather than explicitly declaring them yourself.
  4. Mocking: a groovy testing tool/trick to orchestrate your tests at a higher level.
These concepts are a lot of fun to read, but many people say “yah so what” – and that’s the focus of this post: to tie the strings together.

Our App So Far

I’ve been using my blog project (building my own blog) as the basis for my examples, and I’ll keep doing that for this post. Here’s what we have so far (I’m using ASP.NET MVC):
IPostRepository repo;

public PostController(IPostRepository postRepository){
   repo=postRepository;
}

public ActionResult Index(){
   var posts=repo.GetPosts();
   return View(posts);
}
and I’ve wired up IoC using StructureMap to inject my IPostRepository for me:
public class BlogRegistry : Registry {
        protected override void configure() {

            ForRequestedType<IPostRepository>()
                .TheDefaultIsConcreteType<SQLPostRepository>();

        }
    }
Many people have asked me: “I don’t see how you’re using IoC here – you’re not calling for the Container anywhere” – and that’s true. I left that part out as I didn’t want to derail the point on the innards of ASP.NET MVC. But I will address it here.

Wiring IoC to MVC

What you’re about to see is why so many people like ASP.NET MVC: it’s modular and clean in terms of its parts. Yes you can do this with Web Forms – most likely by using inheritance with System.Web.Page – but there are issues with doing it this way since inheritance is another form of coupling (tying your classes to an architecture or implementation). What would be much better is to “shiv” something in – use some Code Fu to work in this change without a lot of pain. And you can do just this with a thing called a ControllerFactory – which is a core piece of ASP.NET MVC. They have a single responsibility which is to find and create the Controller that your route is asking for. If a user comes to my app and requests “http://myblog/post/index” – routing will dissect this and see that I want to use the PostController and execute the Index action – all good. It’s all magic and “just works” – but the good news is that Phil and team have left back doors in the framework just about everywhere, so we can shimmy-shake it as we need to (another reason why ASP.NET MVC is fun). What I really need to do is to intercept the process – right where the Controller is created – and have my IoC create the Controller instead of the core bits. Doing this will allow me to set all kinds of fun injection rules and have at my Controllers as I feel. To do this, I need to create my own ControllerFactory – the thing that creates the Controllers to service the request – and design the process myself:
public class HanaControllerFactory:DefaultControllerFactory {
    protected override IController GetControllerInstance(Type controllerType) {
        IController result = null;
        if (controllerType != null) {
            result = StructureMap.ObjectFactory.GetInstance(controllerType)
                as Controller;
        }
        return result;
    }
}
That’s all there is to it :). You might have been expecting a lot more here – but as I mention above: Phil and team gave the ControllerFactory a Single Reponsibility (following some principle that I can’t recall the name of) – making it easy to implement/override (love you Phil!). Now that I have my ControllerFactory created, I crack open the Global.asax and wire it up:
protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    StructureMapConfiguration.AddRegistry(new BlogRegistry());
    ControllerBuilder.Current.
        SetControllerFactory(new HanaControllerFactory());
}
That’s all there is to it. Now all of my Controllers are “wired” with Inversion of Control, and I can use it from this point on.

Greasing The Wheels With IoC

In the first part of my IoC post I had a comment from Dan A:
In this simplified example above you switched from 3 lines of easily understandable code to something that requires code in the global.asax, another couple classes, and an interface. The end result contains an extra line or two of code, but now the whole thing is “reusable” and can be unit tested. I happen to agree with Joel’s quote which you openly mocked… it *is* more convoluted. It *is* harder to read and grok. And this was an overly simple example… I’m sure it gets more convoluted with large projects.
Fair enough – reading the StructureMap stuff isn’t so easy – but please consider that as far as my application goes, I’ve added 1 dll and about 18 lines of code. What has it bought me? Check it out… Let’s focus on a very real scenario – growth of the application via shifting business needs. Let’s say that I’m building this blog app for my work and so far it’s working as intended – it adds posts, displays posts, etc. My boss comes in and tells me that they want to move to a more CMS-type of system with version control and some rules around publishing. They also want to have the notion of pages as well as posts. Normally you might throw up your hands and say “REWRITE!” – buy you don’t need to. Breaking the requests down, what’s needed is a more formalized way of working with the data – a business layer if you will. In there we’ll do all kinds of fun things like version our posts and so on:
public class CMSService(IPostRepository repo): ICMSService{
    public IList<Post> GetPosts(){
    //...
    }
    public void SavePost(Post post){
    //..
    }

    //other stuff
}
(You’ll have to use your imagination a bit here for more “CMS-y” stuff… and yes I recognize that you’d probably have a few more classes than this. Work with me here people…) Since I want to test my CMSService class I’ve used the Dependency Injection Pattern once again (passing IPostRepository in the constructor), and I’ve also created an interface called ICMSService so I can mock this thing as required. Now I need to refactor my PostController to use the CMSService:
ICMSService _service;

public PostController(ICMSService service){
  _service=service;
}

public ActionResult Index(){
   var posts=_service.GetPosts();
   return View(posts);
}
… and I have to deal with the Container stuff. You might think “aha! THIS is where Conery eats his hat – this is going to be FUGLY”! Keep in mind that all I’ve done to this point is a bit of refactoring to my application – I haven’t touched the IoC stuff at all. Hold on to your hats…
   public class BlogRegistry : Registry {
        protected override void configure() {

            ForRequestedType<IPostRepository>()
                .TheDefaultIsConcreteType<SQLPostRepository>();

             ForRequestedType<ICMSService>()
                .TheDefaultIsConcreteType<CMSService>();

        }
    }
Yes – that would be one line (well, one line broken in half to keep my page from getting too wide). And that one line does 2 things:
  1. It tells StructureMap “whenever you see ICMSService in a constructor – use CMSService” and
  2. It deals with injecting CMSService with IPostRepository *and* injecting the PostController with ICMSService.
That is why IoC is Good Time Fun – as your app grows, shuffling, refactoring, and tweaking your application is an order of magnitude easier.

More Examples

As the application grows I’ll doubtless have to add many things to it – Logging, ValidationEngine, EmailServices, AuthenticationServices – etc. Being a good Cool Kid, I make sure to interface each of them so I don’t take on coupling, and I add them to my IoC registry:
   public class BlogRegistry : Registry {
        protected override void configure() {

            ForRequestedType<IPostRepository>()
                .TheDefaultIsConcreteType<SQLPostRepository>();

             ForRequestedType<ICMSService>()
                .TheDefaultIsConcreteType<CMSService>();

             ForRequestedType<IILogger>()
                .TheDefaultIsConcreteType<NLogLogger>();

             ForRequestedType<IEmailService>()
                .TheDefaultIsConcreteType<SynchroEmailService>();

             ForRequestedType<IAuthenticationService>()
                .TheDefaultIsConcreteType<MSMembershipService>();

             ForRequestedType<IValidationEngine>()
                .TheDefaultIsConcreteType<XMLValidator>();
        }
    }
Now when I need any one of these things – I just ask for them where I need them - even in my Controller:
ICMSService _service;
ILogger _logger;
public PostController(ICMSService service, ILogger logger){
  _service=service;
  _logger=logger
}

public ActionResult Index(){
   var posts=_service.GetPosts();
   //log the posts
   _logger.Info("IoC Rocks...");

   return View(posts);
}
One thing to note: the IoC container handles the instantiation completely, so when I alter the constructor as I’ve done here, I don’t need to change the calling code anywhere else (except for tests). I haven’t really even touched on the best parts yet :). Typically you’d want to have some level of logging in every part of your application – such as your AuthenticationService as well as your EmailService. Once again you don’t want to take dependencies in there (especially on a particular logging engine!) because you very well may reuse them later, or you may change your mind. I have an AuthenticationService and EmailService I use in just about every app I create – it’s what we do – we’re pack rats. Can you imagine what my PostController would look like if I had to inject the logger into it, as well as into my services (that are also passed to the same constructor)? I’d offer a code sample but it makes my brain hurt just thinking about it. This is “Constructors Gone Wild” and it’s really, really ugly. Instead – I’ve opted for IoC – which will inject “stuff” wherever it’s “injectable” – as long as it’s responsible for creating the object in the first place. Since I made my own ControllerFactory – everything else is buttah and IoC “knits” it all together.

Even More Examples

My project has been a success and my manager actually kissed me because I came in under budget and ahead of schedule (his beard is scratchy…). Now he throws me a curve ball and says “hey you know our site’s slowing down a bit – but only when people leave comments. I think we have an issue with sending out emails. With all of our users – that’s a lot of email all at once.” Taking a look at my EmailService I see that “DOH!” – it’s the SynchroEmailService and YES – it’s trying to send emails  synchronously (inline) to n people when a page is submitted. Yikes! That should be asynchronous and put behind a “chron” – or a scheduled job. I spend 3 hours writing up/testing another mailer (“AsynchroEmailService”) – one that sends the email messages to a queue and logs them using my ILogger. And now I have to implement this – how would you do it? I get to do it in one line with IoC:
ForRequestedType<IEmailService>()
                .TheDefaultIsConcreteType<ASynchroEmailService>();
It just doesn’t get easier than that.

But Wait, There’s More!

My boss and the lead engineer are looking over the code I wrote for the AsynchroEmailService and they like it, but the Lead Engineer has been reading his pattern books again and says
Can we do something with a little less memory pressure here?
Memory Pressure? ORLY? I try to convey that the cost of instantiation here is incredibly minimal – almost at the atomic level – but he insists on doing it right and “Can I use a Singleton”. Rather than argue – I say sure (have you ever had this discussion by chance?). Have you ever tried to code a Singleton? It’s not very fun – in fact I’d say that most of us (me especially) are “doin it wrong”. Locks, threading, ick. Once again – IoC’s got my back:
ForRequestedType<IEmailService>()
                .TheDefaultIsConcreteType<ASynchroEmailService>()
                .CacheBy((InstanceScope.Singleton));
Not sure that could be any easier. I could also choose to cache by HttpContext, PerRequest, ThreadLocal, and “Hybrid” (which means, basically, the same as PerRequest but works better for testing). For now I choose “Singleton” to keep my Lead Engineer happy.

Summary

You can do most of these tricks with WebForms as well – but to be honest I’m not sure what the best way is. I’m fairly certain you could do it with inheriting a base class from your Page and then explicitly working with properties (read only):
public class MyPage:System.Web.Page{

   public ICMSService CMSservice{
      get{
        return StructureMap.ObjectFactory.GetInstance<ICMSService>();
      }
   }

}
It’s a lot more manual, as you can see, but this *should* work (warning: I’ve never tried it). I’m hoping that you’re beginning to see (if you haven’t already) that IoC *can be* a complicated thing, to be sure, but hey you work on computers and you’re already ahead of the curve :). If you think your application will grow (which most do), IoC can really become your best friend.


Chris Hardy - October 11, 2009 - Hey Rob,

Really enjoying the posts, something to note - when you create your own ControllerFactory
"public class HanaControllerFactory:DefaultControllerFactory {" it's called HanaControllerFactory then when you hook it up you've called it "KonaControllerFactory()".

Just a little thing but might be confusing, especially since we're on the subject of IoC ;).

Cheers,

ChrisNTR
Chris Hardy - October 11, 2009 - Bah, You've fixed it, feel free to delete these comments. :)
Neal Blomfield - October 11, 2009 - Nice article, carries the example further than many to show the true benefits that start to appear. These benefits only increase as you introduce batch registration - I am not even conscious of the container being present now, it just works.

With regards to using containers with webforms, a better pattern is to use a presenter and request the presenter from the container in the base page, that way you only have to explicitly request one dependency in your page rather than deal with many. e.g.

public class PresenterBasePage : Page where T : IPresenter
{
private T _presenter;
public T Presenter
{
get
{
if( _presenter == null )
{
StructureMap.ObjectFactory.GetInstance();
}
return _presenter;
}
}
}

This can then be used via:

public class CreatePost : PresenterBasePage
{
...
}
Neal Blomfield - October 11, 2009 - bah, all the angle brackets were nerfed. Should have been:

public class PresenterBasePage[T] : Page where T : IPresenter
{
private T _presenter;
public T Presenter
{
get
{
if( _presenter == null )
{
StructureMap.ObjectFactory.GetInstance[T]();
}
return _presenter;
}
}
}

This can then be used via:

public class CreatePost : PresenterBasePage[ICreatePostPresenter]
{

}
Darren Cauthon - October 11, 2009 - Just a thought for those who think even setting up the registries seem like a lot of work: You don't have to. I'm not familiar with StructureMap (I cut my teeth on Unity), but I'm sure there's a simple way to setup simple rules like:

1.) Automatically register all interfaces with their implementations when they are named the same (for example, IAccountRepository and AccountRepository), or
2.) Automatically register all interfaces with their implementations when there's only one implementation.

So when the application starts, it scans your references according to these rules, wires up your IoC container automatically, and you use your classes without any thought about setup! You just create your class, extract an interface, and it appears magically in your IoC container. No config.
Erik - October 11, 2009 - I've been sold for a long time but I just haven't had a project that would take much advantage of the IoC container idea yet. Guess I'll have to start building my own blog too - how's that working out for you by the way?
jdn - October 11, 2009 - Dan A.'s complaint is a legitimate one, and one that needs to be taken seriously.

Once you understand the patterns, everything Rob says about the benefits is, to my experience, correct, and moreover, it allows you to eliminate 80+% of the time normally spent using a debugger and/or launching the application. From a productivity standpoint, this is a key benefit for knowing how to use DI/IOC/Repository, etc.

The difficulty is getting to that understanding. It isn't really a matter of intelligence, but experience.
MrTea - October 11, 2009 - Great article once again.

Unless I'm being thick (very possible - it is a Monday morning)...

public class CMSService(IPostRepository repo): ICMSRepository{

should read

public class CMSService(IPostRepository repo): ICMSService{

and this sentence needs changing to?

"Since I want to test my CMSService class I’ve used the Dependency Injection Pattern once again (passing IPostRepository in the constructor), and I’ve also created an interface called ICMSRepository so I can mock this thing as required."
MrTea - October 11, 2009 - I think that's exactly correct and one of the compounding problems ironically enough is the Internet.

Its very comforting as a junior developer to read articles published on blogs, find the bits that you understand and reassure yourself that you do understand what "everyone else" is doing. However a lot of these posts are potentially damaging if they are viewed as fact and "this is how you should do things".

You can see how bad practice (or even less good practice ;-)) can perpetuate, and and fill the hole left by lack of experience.

Then the people who have learnt (often the hard way, from their own experiences) and have seen real tangible benefits in certain approaches/methods, come on forums/blogs and sound a little bit like they're religious zealots who have "seen the light" and been converted.

This put people's backs up and back we go again around and around in a big vicious circle.
Luke - October 11, 2009 - Just a heads up that the DefaultControllerFactory class contains a breaking change in MVC 2 Preview 2 - the GetControllerInstance method which you override now includes a RequestContext parameter. This means the example controller factory in this post will need modifying if you're working with the preview.

More at http://go.microsoft.com/fwlink/?LinkID=157066.
Mark - October 12, 2009 - Dude! What about readability? Sure, I love the beauty and wondrous backflipping through hoops of the code. It's shiny and swappable. But big brain or not the readability is negatively impacted.
av - October 12, 2009 - Awesome stuff as usual! Thank you
Rob Conery - October 12, 2009 - What are you having a hard time reading?
Rob Conery - October 12, 2009 - Egads! Thanks - fixed.
Adam - October 12, 2009 - You can do it just like this.


public class MySiteRegistry : Registry
{
public MySiteRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.WithDefaultConventions();
});
}
}
MrTea - October 12, 2009 - I don't see how readability of the controller is negatively impacted and surely that's where the majority of your time when writing new functionality will be spent.

In an Action/Method, instead of creating a new instance of a class, you can just call the one that already exists as a field, leading to less code in each method.

So when you come back to maintain the application and look at a given Method, you don't have to read a whole load of instantiations, you can just see that something called "logger" or "postRepository" is being asked to do something.

If it's relevant at that point to dig deeper into how those objects actually perform their functions you can, if however you're only interested in the flow of that Method (or the logic contained within that Method) you can ignore the inner workings of the "logger" or the "postRepository". In fact, another member of your team entirely could write the implementation for "postRepository" and you might never need to understand how it works.
Mark - October 13, 2009 - Exactly what MrTea picked up on and described as a non-issue below. If I come back to the code after 3 months or want someone else to add something then there is a definite hurdle in understanding where instances are coming from and whose responsibility it was to create them. Some stuff is handled automagically and some is not. How do I know when I read the code for the first time? Where do I draw the line in the use of IoC or not in the same codebase?
MrTea - October 13, 2009 - But the controller should never be responsible for creating these instances, if it is that's a clear violation of the single responsibility principle.

So I guess your concern is not about passing dependencies into the object via the constructor, but the idea of using a framework like Structuremap to do the injection for you?
Gunnar - October 13, 2009 - Hi! Just wanted to ask why are you keeping configuration in code? Are there more than one configuration class implementations available if needed?
Rob Conery - October 13, 2009 - I like to see it in code and I like intellisense :). I think you can use XML config for StructureMap if you want to.
Rob Conery - October 13, 2009 - Your point is one often raised and if I may simplify it: how far do you go to "dumb down" your application to suit your "junior" programmers? If you look at the argument - it's absurd. People will always need time to learn an app they are working on, and doubtless will need to learn some concepts.

You as the lead programmer are in a great spot to show them some good things.

As far as readability goes: Green Eggs and Ham. Just try it try it and you will see :). Seriously - just like your Controllers it really doesn't matter what object is passed in - it's an interface.

It seems like the DI part is more to your dislike am I right? Either way - give it a whirl and I promise you'll dig it :). So will your team - and always challenge others to broaden their reach.
GC - October 13, 2009 - Can you really put the (IPostRepository repo) dependency in with the "class" declaration like that? I've always seen the
public class CMSService:ICMSService {

public CMSService(IPostRepository) { ...
anton - October 13, 2009 - Can all this registry stuff be put inside a config? Everytime you change an something in the registry you will need to re-compile/re-deploy?

Any pros/cons using code vs config to wire up the registry?
Mark - October 15, 2009 - OK - I tried it and I am getting a good vibe ;)
I did however run into a few issues (that were fairly easy to resolve):

I used the default AccountController and all of a sudden I had to wire up default types to be instantiated for these because of the constructors. Your example
ForRequestedType().TheDefaultIsConcreteType();
ForRequestedType().TheDefaultIsConcreteType();
ForRequestedType().TheDefault.Is.Object(Membership.Provider);

It seems your examples are based on an earlier version of StructureMap because StructureMapConfiguration is now obsolete.
Rob G - October 17, 2009 - Yes - a MASSIVE pro for using code instead of (xml) config is refactoring support. It's strongly typed firstly (instead of a string in your xml file), and when (not if) you rename your classes using Visual Studio or ReSharper, the rename percolates down to your config code class as well, meaning that once it's setup, you probably only ever open it again to add more mappings - but if you use the (Scan => x) options - my personal favourite - neither of the two is really required for most things as long as you stick to convention in your naming. Convention over Configuration all the way man!
alwin - October 20, 2009 - Just 198 more posts like these, and you've proved Joel is right. :)

I wouldn't mind though, keep them coming!
Gecko