This dependency injection madness must end!

Or: Poor man’s dependency injection: Singleton-initialized field

As dependency injection frameworks like Spring have become central in software applications in the last few years, the conventional view is now that the Singleton pattern is evil and should never be used. Instead, relationships between objects in your system should be managed by a dependency injection container. I have started disliking the consequence of this strategy very much: All coupling in my system becomes implicit and harder to understand. I have instead reverted to using design patterns like the Singleton pattern, but with a slight twist.

The Singleton-initialized field

Here is an example of a Singleton-initialized field:

<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PersonService <span style="color: #009900;">{</span>
 
    <span style="color: #000000; font-weight: bold;">private</span> PersonDao personDao<span style="color: #339933;">;</span>
 
    <span style="color: #000000; font-weight: bold;">public</span> PersonService<span style="color: #009900;">(</span>PersonDao personDao<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">personDao</span> <span style="color: #339933;">=</span> personDao<span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
 
    <span style="color: #000000; font-weight: bold;">public</span> PersonService<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        SessionFactory sessionFactory <span style="color: #339933;">=</span> 
              MyHibernateContext.<span style="color: #006633;">getSessionFactoryInstance</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">personDao</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HibernatePersonDao<span style="color: #009900;">(</span>sessionFactory<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
 
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> someServiceMethod<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
       <span style="color: #666666; font-style: italic;">// Do something with personDao</span>
    <span style="color: #009900;">}</span>
 
<span style="color: #009900;">}</span>

When I write a test for this class, the test code overrides the PersonDao by passing it to the non-default constructor.

@Test
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> shouldDoSomething<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
   PersonService service <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PersonService<span style="color: #009900;">(</span>mockPersonDao<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
   service.<span style="color: #006633;">someServiceMethod</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
   verify<span style="color: #009900;">(</span>mockPersonDao<span style="color: #009900;">)</span>.<span style="color: #006633;">findAllPeople</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>

Compared: The dependency injection way

The now-conventional way of doing the same thing is with dependency injection:

<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PersonService <span style="color: #009900;">{</span>
 
    <span style="color: #000000; font-weight: bold;">private</span> PersonDao personDao<span style="color: #339933;">;</span>
 
    @Inject
    <span style="color: #000000; font-weight: bold;">public</span> PersonService<span style="color: #009900;">(</span>PersonDao personDao<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">personDao</span> <span style="color: #339933;">=</span> personDao<span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
 
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> someServiceMethod<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
       <span style="color: #666666; font-style: italic;">// Do something with personDao</span>
    <span style="color: #009900;">}</span>
<span style="color: #009900;">}</span>

And the test will set up the dependencies using a container:

@RunWith<span style="color: #009900;">(</span>SpringTestRunner.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">)</span>
@Configuration<span style="color: #009900;">(</span><span style="color: #0000ff;">"src/test/resources/test-context.xml"</span><span style="color: #009900;">)</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PersonServiceTest <span style="color: #009900;">{</span>
 
   @Resource
   <span style="color: #000000; font-weight: bold;">private</span> PersonService service<span style="color: #339933;">;</span>
 
   @Resource
   <span style="color: #000000; font-weight: bold;">private</span> PersonDao mockPersonDao<span style="color: #339933;">;</span>
 
   @Test
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> shouldDoSomething<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
      service.<span style="color: #006633;">someServiceMethod</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
      verify<span style="color: #009900;">(</span>mockPersonDao<span style="color: #009900;">)</span>.<span style="color: #006633;">findAllPeople</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">}</span>
<span style="color: #009900;">}</span>

Somewhere in the realms of test-context.xml we will configure the fact that PersonDao should be provided by a mock:

<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MyDependencyConfigTest <span style="color: #000000; font-weight: bold;">extends</span> MyDependencyConfig <span style="color: #009900;">{</span>
    @Bean
    <span style="color: #000000; font-weight: bold;">public</span> PersonDao personService<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> MockPersonDao<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
<span style="color: #009900;">}</span>

The problem: Declarative programming

With a dependency injection container, the components in my code are loosely coupled. Indeed, this is the main selling point of dependency injection. But sometimes, loosely coupled code is the problem.

First, understanding which dependency is actually used (and why!) can require a lot of brain power: It will require you to consider all possible configurations when you look at a dependency and it will not work well with the normal code navigation functionality of your IDE. Second, the configuration will tend to deteriorate: When you no longer use a dependency, will you check whether you can remove it, or will you just leave it there to be safe?

Lastly, it can be hard to spot errors in the configuration:

I once had a service that needed had a @Resource TransactionManager and a @Resource DataSource. However, the system had a pair of each. The test code was correct, but in the production code, I had by accident configured the wrong TransactionManager. The effect was that the Service didn’t run in a transaction for the correct data source. That is: It didn’t really run in a transaction. The problem with this is that you only discover the problem if you scrutinize the contents of the database after the transaction was supposed to be rolled back.

Dependency injection in specific and declarative programming in general mean More Magic. More Magic is seldom a good thing, at least not when there are simple, time-tested strategies that work. Even if said strategies have fallen out of fashion.

This dependency injection madness must end!

This story, "This dependency injection madness must end!" was originally published by JavaWorld.

Related:

Copyright © 2010 IDG Communications, Inc.