Software Quality

September 16, 2010

automatic dependency injection requires a different style of object and constructor design

Filed under: Practices — David Allen @ 5:12 am

Problem:  Thanks to the amazing book Dependency Injection in .Net, but Mark Seemann, I recently learned how to use automatic dependency injection, but I experienced a lot of friction with my existing object designs and my approach to object construction. Why is that? Well, it has to do with my personal history, and the gaps in my education. 

  I learned OO principles of object construction and Inversion Of Control long before I learned how to use Inversion of Control containers like the Unity or Castle Windsor containers. But I never understood layered applications very well. I had the general idea, but I sometimes put classes in the wrong layer. My struggle is around a core principle of OO design: a constructor is used to prepare an object for use. When the constructor is done, the object should be valid and ready for use.  But what is “ready for use?” It varies by context. 

Before I read Mark’s book,  I had acquired the habit of writing code like this:

public class Foo
{
   IService _service;
   int _accountNumber;
   public Foo(IService service, int accountNumber)
   {
      _service = service;
      _accountNumber = accountNumber;
   }
   public void SaveAccount()
   {
       _service.Save(_accountNumber);

   }
}
public class Program
{
     public static void Main()
     {
        Foo foo = new Foo(new Service(),1234);
        foo.Save();
     }
}

In this design, my Foo class is responsible for saving accounts to the database. It needs an account number to do that and a service to do the dirty work.

However, when I recently learned about automatic dependency injection containers, I found that I was no longer instantiating Foo by hand.  The container would instantiate the constructor arguments for me.  This was a great convenience for the services like IService. But it obviously does not work so well for integers and strings and the like.  In those cases, it would provide a default value (like zero for an integer) .  Instead, I had been accustomed to passing in context-specific values like account number, name, etc… So I had to adjust my style of coding and design to be like this:

public class Foo
{
   IService _service;
   public Foo(IService service)
   {
      _service = service;
   }
   public void SaveAccount(int accountNumber)
   {
       _service.Save_accountNumber);

   }
}
public class Program
{
     public static void Main()
     {
        Foo foo = new Foo(new Service(),1234);
        foo.Save();
     }
}

It appears that both Foo classes are valid designs. But the second is useable with automatic dependency injection, and the first is not. 

Additionally, there are some class designs where context-specific value types are required for an object to be valid, and thus, these values should be passed into the constructor. But the trick is to recognize that these are value objects that either consume services or are consumed by services. But they should not IMPLEMENT services. They should not because that would violate the Single Responsibility Principle (SRP).  Since they should not implement services, then they need not be injected into classes which consume those services. And thus, there is no longer a conflict with automatic DI injection.  Obviously, the must be instantiated by the consumers that need them instead.  I never realized the drawbacks to comingling value objects with service objects until I tried to do DI properly.   Using proper DI injection patterns has forced me to clean up this and other aspects of my designs. What I love most about Mark’s book is the fact that it shows you how all these design practices reinforce one another.

I may have gotten this wrong, but I feel like I’m headed in the right direction anyway.

If you have stories about this sort of design, I’d love to hear them.

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: