Archive for November, 2010

Retrospective techniques

At the Smidig 2010 Agile User Group confererence in Oslo, I conducted an open space workshop where I tested out a few retrospective techniques on the participants.

The workshop was very well attended, and so I’ve posted a Norwegian language summary on the company blog for Steria Norway. Go check it out if you understand Norwegian!

Comments (3)

The effective product owner

I’ve published a Norwegian language article titled: “Min supre produkteier” (“My excellent product owner”) at the company blog for Steria Norway. Go check it out if you understand Norwegian!

Comments

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:

public class PersonService {
 
    private PersonDao personDao;
 
    public PersonService(PersonDao personDao) {
        this.personDao = personDao;
    }
 
    public PersonService() {
        SessionFactory sessionFactory = 
              MyHibernateContext.getSessionFactoryInstance();
        this.personDao = new HibernatePersonDao(sessionFactory);
    }
 
    public void someServiceMethod() {
       // Do something with personDao
    }
 
}

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

@Test
public void shouldDoSomething() {
   PersonService service = new PersonService(mockPersonDao);
   service.someServiceMethod();
   verify(mockPersonDao).findAllPeople();
}

Compared: The dependency injection way

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

public class PersonService {
 
    private PersonDao personDao;
 
    @Inject
    public PersonService(PersonDao personDao) {
        this.personDao = personDao;
    }
 
    public void someServiceMethod() {
       // Do something with personDao
    }
}

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

@RunWith(SpringTestRunner.class)
@Configuration("src/test/resources/test-context.xml")
public class PersonServiceTest {
 
   @Resource
   private PersonService service;
 
   @Resource
   private PersonDao mockPersonDao;
 
   @Test
   public void shouldDoSomething() {
      service.someServiceMethod();
      verify(mockPersonDao).findAllPeople();
   }
}

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

public class MyDependencyConfigTest extends MyDependencyConfig {
    @Bean
    public PersonDao personService() {
        return new MockPersonDao();
    }
}

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!

Comments (12)

Video: No-red refactoring

The more I code, the more I’ve learned to appreciate keeping the code clean even during complex refactorings. By “clean”, I mean that the code always compiles and the test always run.

I often find myself in a situation where I have a method call that’s starting to accumulate parameters. Something like this:

showPersonCreateForm(writer, firstName, firstNameErrorMessage, lastName, lastNameErrorMessage,....);

After three or four parameters, the need to refactor is starting to become evident. I would rather have something like this:

CreatePersonForm form = new CreatePersonForm();
form.setFirstName(firstName);
form.setFirstNameErrorMessage(firstName);
form.setLastName(firstName);
form.setLastNameErrorMessage(firstName);
form.show(writer);

This is one of the more complex simple refactorings you can make, and it requires several steps. In this five minute video, I show how to perform such a refactoring without any steps that break my code:

The screencast was created using the free BB FlashBack Express on Windows. All the magic you see happening while I program is either ctrl-space (complete) or ctrl-1 (quick fix).

Can you modify your code without going thought long stages of nothing working? I think you can!

Comments (1)

Creative Commons Attribution 3.0 Unported
This work is licensed under a Creative Commons Attribution 3.0 Unported.