Tuesday, February 12, 2013

Dependency Injection Lite


So here is the problem. I have objects that I want to use in many different places. These objects don't have much state, but I end up passing them around all over the place just in case I want to use them. Now passing an object is nice because you are saying, "Hey this method requires this object" and this statement is very helpful to people reading the code, but you can get into longs chains where you pass tons of objects into a method because sub-objects/sub-methods might need those objects. Then it goes from being clear to being confusing. So there are a couple patterns I could use. One is singletons and another is a depenency injection framework, but I have something that is a little in between that leans more towards the "fluent".

Here is the basics on the usage of the Singleton pattern:

SingletonObject obj = SingletonObject.getInstance();
obj.MyMethod();

Now I have seen a decent amount of criticism that singletons cause testing problems and really just conceal global state.  So we should keep those criticisms in mind.

So dependency injection is becoming more and more popular because it makes testing easier. So the usage pattern is like the following:

IObjectOfInterest obj = DependencyInjectionFramework.Get<IObjectOfInterest>();
Obj.MyMethod();

The DependencyInjectionFramework object is set up by configuration such that for X interface you get Y object. For testing we do something like:

DependencyInjectionFramework.InjectStub(typeof(IObjectOfInterest), new MyMock());
DependencyInjectionFramework.ResetDefault();

So given these two very common patterns I have a kind of play on them that I have been using frequently. Since I do web development it is geared for the web.


public class RepositoryFor
{
private const string ObjectTypeKey = "ObjectTypeKey";
private static IObjectTypeRepository _objectTypeRepository;

public static IObjectTypeRepository MyObject
{
    get
    {
        if (_objectTypeRepository!= null)
        {
            return _objectTypeRepository;
        }
        if (HttpContext.Current.Items.Contains(ObjectTypeKey))
        {
            return (IObjectTypeRepository) HttpContext.Current.Items[ObjectTypeKey];
        }
        IObjectTypeRepository repository = new ObjectTypeRepository();
        HttpContext.Current.Items[ObjectTypeKey] = repository;
        return repository;
    }
}

public static InjectMyObjectStub(IObjectTypeRepository stub) 
{
    _objectTypeRepository = stub;
}

public static RestoreDefaults()
{
    _objectTypeRepository = null;
}


}

With the usage pattern being:

RepositoryFor.MyObject.MyMethod();

And the unit testing pattern being:

RepositoryFor.InjectMyObjectStub(new MyMock());
RepositoryFor.RestoreDefaults();

You can see this pattern is a lot like the dependency injection pattern. The key thing is the default constructor is defined by code and not by configuration. You also have objects grouped by the static wrapper. In the example this is RepositoryFor but you could add others like BusinessFor, HandlerFor, and so on.

So a couple points on this pattern.

  1. Thread singletons vs. statics
In a web server context you can use ThreadStatic, but I have seen some evidence that it is better to store objects in the HttpContext.Items collection because a request can be transferred between threads. So you can see here that the HttpContext.Items collection is for when the code is running as part of the webserver and the static variable backing this is for a testing context. Note that one nice piece of this is that it isolates the  HttpContext.Items collection which is a collection that can easily be misused.

To ensure that the variable is only used in a testing context you could use a preprocessor variable or do something like ensuring that HttpContext.Current == null in the setter.

  1. Do you want global access?
You can make a valid argument that creating globally accessible objects is bad architecture and that you are creatign a pattern that allows poor design to flourish. So patterns can be used badly. So there is that… I think in most cases this pattern can be helpful and make code clearer. I have mainly used this for repositories and business logic objects.

  1. No private constructors…
The nice thing about the Singleton pattern is that it has a private constructor. This is nice because you are sure that only one can ever be created, but then you have the testing problem. In this mechanism your constructors are not private so you could have people make calls to these constructors. So this is something you give up for testability.

  1. Code over Configuration
So this uses code instead of configuration. This is because in practice you don't want to change things that much so configuration doesn't make much sense. Configuration is also problematic when people get out of sync. Keeping code in sync tends to be easier because you always want 100% code sync. So while this is less flexible, I argue that you don't really need so much flexibility.

Okay, so why do this instead of using a full blown DI framework? Well, it isn't much work and you can avoid adding a new tool that people have to learn. You can use code to define behavior instead of configuration (tastes may vary). Basically you can use this pattern to start using a DI style of doing things without taking the full plunge. Also, when you do decide to switch to a DI framework the transition will be very easy.

No comments:

Post a Comment