Apr 17 2010

Dependency Injection Flavors - The Good, The Bad and the Ugly

Category: Software DevelopmentJeff @ 08:19

UPDATE: check out the code at http://codepaste.net/t4z78p if the stuff below isn't formatted well for your browser.

using System;
using NUnit.Framework;

namespace DependencyInjectionApproaches
{    
    /// <summary>
    /// There are multiple flavors of Dependency Injection - 
    /// 
    /// 1) Constructor injection - dependencies are passed in as constructor parameters
    /// 2) Setter injection - dependencies are passed in to setter methods
    /// 3) Service locator - dependencies are registered with a static gateway which serves up 
    ///     the dependencies (not really dependency *injection* per se, but let's not be sticklers)
    /// 4) PMDI - Poor Man's Dependency Injection (more to come on this one later)
    /// 
    /// I've found that Setter Injection (SI) and Service Locator (SL) have an inherent problem 
    /// because they hide dependencies.  If my class-under-test uses SI or SL, then I often have 
    /// to inspect the source of the class to understand which dependencies must be wired up for 
    /// testing the class.  With Constructor Injection (CI), all of the dependencies are right 
    /// there in the constructor.  There are quite a few other issues related to this matter
    /// which I will discuss below in the context of demonstrating each flavor of dependency 
    /// injection.
    /// 
    /// I've defined an interface "IService" and with multiple implementations.  Each concrete
    /// implementation depends on "ILogger". This dependency is resolved in different ways
    /// for each concrete implementation of IService.
    /// </summary>
    [TestFixture]
    public class DependencyInjectionSpecs
    {
        [Test]
        public void using_constructor_injection()
        {
            var testLogger = new TestLogger(); // Moq would be better, but trying to focus on DI here
            var sut = new ConstructorDependentService(testLogger); 
            
            sut.DoWork();
                        
            testLogger.LastMessage().ShouldEqual("ConstructorDependentService did work");
            
            // (*) when I build the System-Under-Test (sut) see how I can't even call the constructor 
            // without the dependency?  that's good.
            // also notice that I'm only testing my System-Under-Test (SUT) in its interaction with
            // a single dependency.  Good unit tests usually look like this. They only test one class 
            // in its interactions with one abstraction of a dependency.
        }
        
        [Test]
        public void forgetting_to_wire_up_dependency_in_setter()
        {
            var sut = new SetterDependentService();
            
            sut.DoWork(); // throws a NullReferenceException        
            
            // Oops.  I'm able to create my SUT, but I can't execute the DoWork method on it.  Why not?
        }
        
        [Test]
        public void remembering_to_wire_up_dependency_in_setter()
        {
            var testLogger = new TestLogger();            
            var sut = new SetterDependentService();
            sut.Logger = testLogger; // Note this extra requirement for the test to work (*)
            
            sut.DoWork(); 
            
            testLogger.LastMessage().ShouldEqual("SetterDependentService did work");
            
            // (*) That's better than the last test, but more work than the first one.
            // I can still make this test pass, but there's an extra setup cost.  Note that the 
            // dependency is hard to see immediately (we missed it in the previous test).
            // With constructor injection I get a compliation error if I don't set up the dependency.  
            // With setter injection, the missed dependency is not discovered until run time.  Oops.
        }
        
        [Test]
        public void forgetting_to_wire_up_dependency_in_service_locator()
        {
            var sut = new ServiceLocatorDependentService(); // Crud! - KeyNotFoundException (*)
            
            // (*) The test throws immediately due to lack of service registration. Even worse, the 
            // dependency is completely opaque. At least with setter injection I could inspect the 
            // SUT with intellisense, now I'm totally hosed.  I have to look at the implementation 
            // of ServiceLocatorDependentService to figure out how to test it (or if I can at all).
        }
        
        [Test]
        public void remembering_to_wire_up_dependency_in_service_locator()
        {
            var testLogger = new TestLogger();
            ServiceLocator.Configure<ILogger>(() => testLogger); // additional complexity - see below (*)
            var sut = new ServiceLocatorDependentService();
            
            sut.DoWork(); 
            
            testLogger.LastMessage().ShouldEqual("ServiceLocatorDependentService did work");
                        
            // (*)  I'm no longer testing my System-Under-Test in isolation with its dependency, 
            // but I'm also testing my ability to register and resolve dependencies with my Service Locator.
            // This gets worse when my SUT has multiple dependencies which must be resolved from the 
            // Service Locator.
        }        
        
        // PMDI = "Poor Man's Dependency Injection"
        // PMDI may seem like a nice compromise.  You get a default parameterless constructor which uses
        // default implementations of dependencies.  The trouble arises when you want to modify the 
        // constructor of one of *those* dependencies.  What if DefaultLogger changes to require a 
        // constructor parameter? Now changes ripple to all classes that use PMDI with DefaultLogger.
        
        [Test]
        public void PMDI_is_tempting_you()
        {
            var sut = new PoorMansDependencyInjectedService();
            
            sut.DoWork();                
            
            // There is nothing to assert, nothing I can test.  I could visually check my console output, 
            // but doesn't that defeat the whole purpose of an *automated* unit test?
        }
        
        [Test]
        public void PMDI_wants_you_to_come_to_the_dark_side()
        {
            var testLogger = new TestLogger();
            var sut = new PoorMansDependencyInjectedService(testLogger);
            
            sut.DoWork();
                
            testLogger.LastMessage().ShouldEqual("PoorMansDependencyInjectedService did work");

            // yes, it passes.  and with the *same* number of lines as the first example with 
            // constructor injection.  but consider the costs.
            
            // 1) DefaultLogger might change to have constructor arguments (rippling problems, 
            //    but at least caught at compile time)
            // 2) DefaultLogger might change to have setter injected dependencies (now you're 
            //    really hosed! runtime exception!)
            // 3) this is really an SRP violation (Single Responsibility Principle).  Your class 
            //    is not only doing its own job, but is also tasked with determining its appropriate 
            //    defaults.  I suggest you centralize this code in an application bootstrapper and 
            //    find a better way to resolve default implementations (incidendally, StructureMap
            //     has some spectacular abilities in this regard).

            // my last word on PMDI:
            // it seems to me that PMDI is just an attempt to avoid teaching Dependency Injection 
            // to people. I think we're better off showing people all the options and explaining 
            // the pros/cons of each. Perhaps even PMDI has it's place, but it shouldn't just be 
            // the knee-jerk default.  For a shining example of the abuse of PMDI, check out 
            // many of the samples Microsoft released for ASP.NET MVC 1
        }
                    
        #region test support code not relevant to the discussion of dependency injection
        
        [TearDown]
        public void after_each_test_method_executes()
        {
            // make sure we have a clean service locator after each test run.
            // otherwise a registered service from a previous test run can affect
            // the results of other tests, causing false positives or false failures
            // (both really, really bad).
            ServiceLocator.Reset(); 
        }        
        
        #endregion        
    }    
    
    #region more test support code not relevant to the discussion of dependency injection

    public static class SpecificationExtensions
    {
        public static void ShouldEqual(this string actual, string expected)
        {
            Assert.AreEqual(expected, actual);
        }
        
        // check out the NUnit.Specs project for a library of fluent wrappers
        // for NUnit assertions:
        // http://nunitspecs.codeplex.com/
        // I think they are much more clear and concise than the out-of-the-box
        // assertion syntax of NUnit.
    }
    

    #endregion        

    public interface ILogger
    {
        void Log(string message);
    }
    
    public class DefaultLogger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine(message);
        }
    }
    
    /// <summary>
    /// Yes!!! - I would much rather use a Mocking framework like Moq, but I
    /// don't want to muddy the waters since the focus here is on learning
    /// dependency injection.  
    /// </summary>
    public class TestLogger : ILogger
    {
        string _lastMessage;
        
        public void Log(string message)
        {
            _lastMessage = message;
        }
        
        public string LastMessage()
        {
            return _lastMessage;
        }
    }
    
    /// <summary>
    /// I hate xml comments, but in this context they just might help you.  :)
    /// </summary>
    public interface IService
    {
        void DoWork();
    }
    
    /// <summary>
    /// Implementation of IService using Constructor Injection
    /// </summary>
    public class ConstructorDependentService : IService
    {
        ILogger _logger;
        
        public ConstructorDependentService(ILogger logger)
        {
            _logger = logger;
        }
        
        public void DoWork()
        {
            _logger.Log("ConstructorDependentService did work");
        }
    }

    /// <summary>
    /// Implementation of IService using Setter Injection
    /// </summary>
    public class SetterDependentService : IService
    {
        ILogger _logger;
        
        public SetterDependentService() { }
        
        public ILogger Logger { internal get { return _logger; } set { _logger = value; } }
        
        public void DoWork()
        {
            _logger.Log("SetterDependentService did work");
        }
    }
    
    /// <summary>
    /// Implementation of IService using Service Locator
    /// </summary>
    public class ServiceLocatorDependentService : IService
    {
        ILogger _logger;
        
        public ServiceLocatorDependentService()
        {        
            _logger = ServiceLocator.GetInstance<ILogger>();
        }        
        
        public void DoWork()
        {
            _logger.Log("ServiceLocatorDependentService did work");
        }
    }
    
    /// <summary>
    /// Bonus! Implementation of IService using Poor Man's Dependency Injection
    /// </summary>
    public class PoorMansDependencyInjectedService : IService
    {
        ILogger _logger;
        
        public PoorMansDependencyInjectedService() : this(new DefaultLogger())    { }
        
        public PoorMansDependencyInjectedService(ILogger logger)
        {
            _logger = logger;
        }
        
        public void DoWork()
        {
            _logger.Log("PoorMansDependencyInjectedService did work");
        }
    }
    
    /// <summary>
    /// NOTE: this is a terrible implementation of a service locator the only purpose of which
    /// is to demonstrate the pitfalls of overreliance on ServiceLocation in your classes.
    /// *IF* you are going to do service location, you're better off using the implementation
    /// from a Dependency Injection framework (like StructureMap's "ObjectFactory").
    /// You might also consider the CommonServiceLocator project:
    /// http://commonservicelocator.codeplex.com/
    /// In general, however, I recommend you steer clear of service locator until you grok
    /// dependency injection enough that you are using constructor injection the majority of 
    /// the time.
    /// </summary>    
    public static class ServiceLocator
    {
        static readonly System.Collections.Generic.Dictionary<Type, Func<object>> Configuration
            = new System.Collections.Generic.Dictionary<Type, Func<object>>();
        
        public static void Configure<TService>(Func<TService> factory)
        {
            Configuration.Add(typeof(TService), () => factory());
        }
        
        public static TService GetInstance<TService>()
        {
            var factory = Configuration[typeof(TService)];
            return (TService)factory();
        }
        
        public static void Reset()
        {
            Configuration.Clear();
        }
    }
}

Tags: , , , ,

Mar 18 2009

ASP.NET MVC Version 1 Has Shipped

Category: Software DevelopmentJeff @ 22:12
Version 1 of Microsoft's ASP.NET MVC framework has shipped.  Find out more about the framework or go download it.

Tags:

Dec 2 2008

ToFormattedList Extension Method

Category: Software Developmentemilioc @ 05:54

Forgive me if this incorrect, but I believe the ToFormattedList() IEnumerable extension method was part of the early ASP.NET MVC previews.  If you’ve used the method then you are aware of its usefulness.  You pass in a format string (ex. “<li>{0}</li>”) and you get back a string of all the objects that were in your IEnumerable individually formatted ("very nice" -Borat).  This is perfect if all the objects in your IEnumerable have an acceptable ToString() method. What if you are working with POCOs or business objects and you would like to use a property instead of an objects ToString() value?  This is exactly the scenario that prompted me to create a ToFormattedList() extension method for IEnumerable<T>.  

To satisfy this new requirement I needed to add a new parameter.  My version of ToFormattedList() takes a Func<T, string> parameter to access the appropriate property (we need the func, we gotta have that func).  Below is the simple code that makes this work and example of its use.

Code

    public static string ToFormattedList<T>(this IEnumerable<T> list, string format, Func<T, string> func) {
        var s = "";

        foreach (T item in list) {
            s += string.Format(format, func.Invoke(item));
        }

        return s;
    }

Usage

    var output = companies.ToFormattedList("<li>{0}</li>", c => c.Name);

Tags: , ,

Nov 13 2008

Strongly Typed Model Object Without Code-Behind (Sort of)

Category: Software Developmentemilioc @ 20:21

Are you using ASP.NET MVC?  Do you want a strongly typed ViewData.Model object without a code-behind file?  Tough, who said life was fair?  I am just kidding ;p. 

After reading Look Ma, No Code-Behind! by Chad Myers, I was inspired to share my approach.  In my approach, I swap a code-behind file for an ordinary class file.  I create a file per view folder named _ViewDataModelType.cs.  The file name is optional and can be changed per view folder.  I like to use the same name over and over because I am lazy.

Setup

In this file I declare all the ViewPage and ViewUserControl subclasses needed for this particular view folder.  Use your namespaces wisely because if you're not careful you can run into naming collisions.  Below is an example of what one these classes might look like.

namespace NoCodeBehind.Views.Employee {
    public class EmployeeIndex : ViewPage<IEnumerable<Employee>> {
    }

    public class EmployeeShow : ViewPage<EmployeeViewModel> {
    }

    public class EmployeePartial : ViewUserControl<EmployeePartialViewModel> {
    }
}

Usage

All you need now is to wire up your .aspx page.  The Inherits attribute is the important piece.  Below is an example.

<%@ Page Language="C#" AutoEventWireup="true" Inherits="NoCodeBehind.Views.Employee.EmployeeIndex" %>

After that, you are done.  You now have a strongly typed model object at your finger tips. 

Conclusion

Using a code-behind file for every view page is a non-option for me.  This is a simple work around and helps keep my project slim around the waistline.  I am definitely open to other solutions to this issue.  I hope this helps if you are wrestling with the same issue.

Tags: