What’s so great about Inversion of Control?

Inversion of Control (IoC) is an essential tool for any software designer’s design toolbox because it’s often a great way to break dependencies between classes and promote loose coupling.  IoC is vital for doing Test Driven Development without pulling out all of your hair in frustration. 


 


 


Real Life Example


 


I’m doing an interesting refactoring early this week on some existing code.  I apologize in advance for being a little vague, but the NDA thingy gets in the way a bit here.  The product that my team works on is basically a B2B hub between sender companies (spokes) and receiving companies. 


 


The application:



  1. Receives a message in one of a handful of industry standards and 3rd party formats
  2. Converts the data into a canonical data format
  3. Performs a variety of business validations
  4. Translates the results into yet another industry standard for transmittal to another downstream system

 


The translation code is obviously critical to the system, so it’s very important that the automated testing is rock solid.  Moreover, that code would be extremely useful in many other contexts throughout our enterprise.  The code works just fine and there is a robust suite of automated tests ensuring that the code continues to work.  I had tried in the past to adapt this code inside of an automated regression test tool without any success because it had too much “tail.”  What I mean by this is that the code can only function with some specific dependencies on a couple of different data sources that weren’t necessarily easy or even possible to recreate without bringing in a large fraction of the system.  Using the translation code requires some data access code which in turn requires some configuration code and external settings in a Registry (We’re going to make this go away too.  I detest using the Registry for any configuration, much less as a Plugin strategy.).


 


In an ongoing effort to speed up a slow (15-20 minutes) build, I managed to break the integration tests for the translation classes and had an opportunity to look much closer at this code.  Here’s roughly what I found:


 


      public class Translator1


      {


            private readonly IDataSource _source;


 


            public Translator1(IDataSource source)


            {


                  _source = source;


            }


 


            public Translator1()


            {


                  _source = new CompanyDataSource();


            }


 


            public XmlDocument TranslateFlatFile(byte[] contents, string senderId, string receiverId)


            {


                  XmlDocument document = this.startNewXmlDocument();


 


                  CompanyInfo sender = _source.FetchCompanyInfo(senderId);


                  CompanyInfo receiver = _source.FetchCompanyInfo(receiverId);


 


                  this.createSenderNode(sender, document);


                  this.createReceiverNode(receiver, document);


 


                  // Do a lot of other stuff


 


                  return document;


            }


 


            private void deepInTheBowelsOfTheClass(string key)


            {


                  string something = DataSourceSingleton.Instance.LookupValue(key);


                  // do something with “something”


            }


 


            [OTHER METHODS]


      }


 


And the test fixture looks a bit like this:


 


      [TestFixture]


      public class Translator1TestFixture


      {


            [Test]


            public void WriteTheSenderNode()


            {


                  // The sender and receiver data is assumed to be in the database — somewhere


                  Translator1 translator = new Translator1();


 


                  byte[] contents = this.readFlatFile();


 


 


                  XmlDocument document = translator.TranslateFlatFile(contents, “ID00001″, “ID00210″);


                  XmlNode senderNode = document.DocumentElement.SelectSingleNode(“Sender”);


                  Assert.AreEqual(“Austin”, senderNode["City"].InnerText);


            }


 


            private byte[] readFlatFile()…


      }


 


So what’s so terribly wrong with this code?  From my standpoint there are several problems.


 



  • Setting up the tests.  The unit tests cannot function today without known data being previously setup in the database external to the TestFixture.  When you do write tests against a live database you’re forced into a “least evil” decision.  One of the things I talked about in an earlier post was the desire for tests to reveal the intention of the code.  One of the best ways to do this is to make sure that the test is largely self-contained.  In this case the data assumed to be inserted into the database prior to the test running.  One way we can make this test self-contained is to do the database data setup inside the TestFixture class itself.  That’s okay with small chunks of data, but it doesn’t scale very well. 
  • The tests are not isolated.  The tests break if other tests overwrite the data in the database.  Life is happier by far when each test is truly isolated and order-independent.  The dependency on the singleton in the Translator1 class certainly doesn’t help either.  I’m fighting with a set of tests today that are not isolated.  They exhibit some interesting behavior like running successfully one at a time but failing occasionally when they’re run with other tests.  I’m not happy.
  • Debugging the unit tests.  Look at the WriteTheSenderNode test method.  There is an assertion that checks that the “City” node has a value of “Austin.”  Just looking at the test code you won’t be able to see where this value comes from.  It’s not clear from the test code why the value of the xml node is supposed to be “Austin.”  You can partially beat this problem with comments in the assertions, but that’s not enough in my book.  Comments are often a crutch for obfuscated code and this isn’t an exception.  Another thing to keep in mind is that granular tests are easier to debug than coarse tests.  This code today only has integrated tests without any unit tests.
  • Test execution time.  Tests that run against the database are slower than tests that run completely inside one process.  I’m writing this post while I wait for some very slow integrated tests to run.  Slow tests are a form of inefficiency.  I really want to test the translation code here, not the data access.  If I can isolate the translation functionality away from the database structure, I can make the tests faster.
  • Reuse the code.  As I’ve stated before, it would be very advantageous to reuse this translation code.  Today this is difficult because of the tight coupling to other classes.  The dependency on the specific data access class is easily remedied by a little “constructor injection,” but there is still the dependency on the singleton buried deep inside the class.  To use the translation code I have to bring with me everything that damn singleton needs too.  Moreover, it’s not going to be obvious to someone else attempting to use the translation code what they need without tracing deep into the translation to figure out the external dependencies of the singleton.  Singleton == testing pain.  I haven’t done enough research into the singleton usage, but one way or another we’ll remove the dependency on the singleton.

 


Refactoring to Inversion of Control


 


My thought on the translation code is to apply Inversion of Control to the translation code to remove the database dependency.  Let some other class be responsible for running out and fetching the receiver and sender information and “push” it into the translator.  I could have abstracted the data source class as an interface and used Constructor Injection to push alternative classes or mocks into the Translator2 class.  My thinking in this case is to simplify both the reuse of the translation code and eliminate the mocking overhead (~70 automated tests) by eliminating the interaction with a data source class altogether.


 


The code below is a skeleton of the approach I’m going to take to refactor our translation code (someday).  Here’s how I think the new code stacks up to the old code.


 



  • Setting up the tests.  The input data is created within the test itself because the inputs are just objects.  Don’t ever discount the value of Intellisense in creating test data.  Working with SQL statements or DataSet’s is laborious and error prone.
  • The tests are isolated.  The translation code no longer depends on any kind of external or shared data inside the tests.
  • Debugging.  The tests are somewhat easier to debug because the tests are self-contained.  Debugging one of these tests if they break is simpler because you don’t have to keep “ALT-Tabbing” between the database window and the code.  I’d also argue that the test code is much more intention revealing.
  • Test execution time.  These tests will run faster because the external network hops to the database are eliminated.  Don’t underestimate the importance of fast tests.
  • Code reuse.  I can now reuse the translation code more easily in other contexts.  I don’t have to have any special database structure or external configuration anymore to use the translation code.

 


      public class Translator2


      {


            public Translator2()


            {


            }


 


            public XmlDocument TranslateFlatFile(byte[] contents, CompanyInfo sender, CompanyInfo receiver )


            {


                  XmlDocument document = this.startNewXmlDocument();


 


                  this.createSenderNode(sender, document);


                  this.createReceiverNode(receiver, document);


 


                  // Do a lot of other stuff


 


                  return document;


            }


 


 


            #region other methods


      }


 


      [TestFixture]


      public class Translator2TestFixture


      {


            [Test]


            public void WriteTheSenderNode()


            {


                  CompanyInfo sender = new CompanyInfo();


                  sender.City = “Austin”;


                  // set other sender properties


 


                  CompanyInfo receiver = new CompanyInfo();


                  // set receiver properties


 


                  byte[] contents = this.readFlatFile();


                  Translator2 translator = new Translator2();


 


                  XmlDocument document = translator.TranslateFlatFile(contents, sender, receiver);


                  XmlNode senderNode = document.DocumentElement.SelectSingleNode(“Sender”);


                  Assert.AreEqual(sender.City, senderNode["City"].InnerText);


            }


 


            private byte[] readFlatFile()…


      }


 


All I’ve really done is move the responsibility for fetching data out of the database into another class.  It’s a small change but it had a positive impact on both the code and the testing.  If you think about it, you could actually say that software design boils down to “Where should this code go?”  I think there’s a watershed moment in every developer’s career when they start look more at their code as a structure and less as a bag of statements. 


 


Other Examples


 


We’re taught that the key to safe lifting is “push, don’t pull.”  I like to think of Inversion of Control as applying this mantra to code.  IoC is fairly common, and much more so with Test Driven Development practices.  Here are some other examples of IoC you might run into.


 



  • The Data Mapper pattern is the central concept in many Object/Relational Mapping tools.  Using an external mapper class to handle persistence duties for a business domain class has several advantages.  The domain classes can become simpler because they’re no longer interacting with any kind of data class.  You can also insulate the business domain from the database structure and vice versa.  Testing the business logic can be much simpler with a domain model.  My company’s main application today relies on far too many T-SQL stored procedures.  Some of our multi-billion dollar clients seem to think they have the right to run our application on Oracle instead.  We’re eventually going to arrange our business logic along domain model principles and take advantage of an O/R mapping tool for multi-database support.
  • Model View Presenter (MVP) might not be a true example of IoC, but it’s similar in philosophy.  When you use the MVP you make the “view” classes completely passive.  Instead of the view making requests to the controller, the controller tells the view what to do.  MVP is the best mechanism that I know for doing TDD with user interface clients.
  • A side effect of using Dependency Injection for configuration is that your classes are no longer dependent on any kind of external configuration file (or God forbid, the registry).  Here’s a simple example of “push” configuration.  The PushClass will be constructed by some kind of Builder class that reads the configuration and returns a PushClass object.  I’m a huge fan of this technique after a couple of projects now.

 


      public class PullClass


      {


            private int _threshold;


 


            public PullClass()


            {


                  _threshold = int.Parse(System.Configuration.ConfigurationSettings.AppSettings["Threshold"]);


            }


      }


 


      public class PushClass


      {


            private readonly int _threshold;


 


            public PushClass(int threshold)


            {


                  _threshold = threshold;


            }


      }


 



  • If you look at the example user story from my article on Assigning Responsibilities, I used IoC to isolate the functionality for creating HTML from an Invoice so that this functionality could be tested without a lot of interaction with other classes.

 


The obvious example of IoC from the blogosphere is Dependency Injection.  My next post will be an introduction to Dependency Injection (DI) as a concept independent of the DI/IoC tools.   

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Design Patterns, Test Driven Development. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Andy Nagai

    whats with all the spacing in this post? A  bunch of empty p tags.

  • http://revizyonileorganizematbaacilikbrnckvvtmllttrhaberi.bloggum.com revizyon ile organize matbaacılık brnckvvtmllttrhaberi

    thanks for all

  • Gregory Madsen

    There has been a lot written about Dependency Injection (DI) and Inversion of Control (IoC) and while I think I understand the ideas behind them (separation of responsibility, testability, orthogonality, etc.), there is something nagging at the back of mind that says that doing DI means breaking OO encapsulation. One could almost say that it is a move backwards towards the bad old days where we had data structures and procedures that operated on them. We are now passing the dependencies into the object and asking it to work on them. To me this is not that far removed from passing a structure into a standalone subroutine. I always thought that the idea behind encapsulation was that you could ask the object to do something and you didn’t need to know or care how it did it, but that it just did it. It was up to the object to create or get whatever it needed to do its job. Now we seem to be saying that the object needs to depend on a master object of some kind to give it its data, which smacks of the old “main routine” with subroutines model.

    Now I will admit that over the years I have found my own code moving towards IoC as it seemed the natural thing to do, but back then (2001-2003) I had no idea that it had a name, as I was working mostly on my own. As I worked to improve my code and reduce duplication, etc., it seemed like what was really needed was some sort of a configuration driven “builder” of my classes at run time so that the pieces would be much more reusable and modular. (I hadn’t learned of TDD then.) That particular project ended before I could implement these ideas, and to this day, it retains its awkward design, but it is now the responsibility of others, a decision that I had no control over.

    I guess what it all boils down to is that there are competing interests in software design, and while strong encapsulation of everything sounds good in theory, it falls down a bit in the real world. Maybe I’m answering my own question here, but I guess if one sticks to using well formed interfaces inside a class, then the overall behaviour of that class is in fact fixed and is encapsulated along with its data. What is not fixed by the class design is the actual classes that implement that required behaviour. Subtle, but a very important distinction.

    Does this make any sense to anyone else?

  • http://blogs.telussa.com/danwatts/ Dan

    Great post! Thanks for sharing!

    Another downfall with data access dependancy : If the database is readonly, your test will have to run under a special user to insert test data.