Saturday, May 30, 2015

DI Framework vs DIY-DI

It is common in IT industry to correlate dependency injection (DI) with a DI framework such as Spring DI, or Guice. However, it is possible to do DI on your own with plain java (or the language of your choice). In this post I present some thoughts on the consequences of using or not a DI framework.

Do-It Yourself  DI

A long time ago, Chad Parry shared his proposal for what he calls "do-it yourself DI" or DIY-DI, followed by Google's Misko Hevery evangelizing this approach. Chad Parry's main arguments against DI frameworks were:
  1. the project code becomes tightly coupled to the framework’s syntax, so that it is very difficult to move to another DI framework;
  2. frameworks perform a lot of magic behind the scenes, which is problematic for many reasons, difficult to read the code and understand which dependency is used at each place, realize conflicts at run-time rather than at compile-time to name a few.
DIY-DI is build on the fact that the code can be separated into two different parts, the business logic and the so called 'glue code'. It builds custom injectors, providers and scopes. With scopes one effectively implements a custom container to manage the objects lifecycle. For more details read the DIY-DI proposal.

DIY-DI relies upon the developers discipline to stick with a clear separation of glue code and business logic as presented in the following table.

Glue Code Business Logic
Lives only in main and the injector classes Is not allowed in main or the injector classes
Frequently invokes other injection helpers Cannot reference any injection helpers
Uses scope objects for method parameters Only sees scope objects at the start of a new scope
Can construct any object Avoids the new operator
Contains only trivial glue code Can contain arbitrary logic
Is scenario tested but not unit tested Is covered by scenario tests and unit tests

A Critical View

At the time (2010) DIY-DI was proposed, the predominant way to do DI was Spring DI with XML configurations, the analog of 'glue code'. The idea to separate the glue code from the programming language into a XML configuration files came out of control for big projects. Above a codebase size it is literally impossible to understand which dependency is used without running the app and pausing with breakpoints. But java configuration has much improved the situation. Nowadays, java configuration is the standard for greenfield projects. You have to deal with XML configuration only when maintaining legacy systems.

Also the argument about tight coupling your app with the DI framework, although correct, is more of an academic flavor, rather than solving an industry problem. In real world, the decision to change DI framework should happen very rarely, or almost never to be realistic. Progress is also done in this field as both Spring DI and Guice adhere to standard javax annotations, e.g. in Spring DI you can write "@Inject" instead of "@Autowire".

Probably the biggest argument for DIY-DI is that it is the lightest solution for DI, although lightweight DI frameworks have emerged (see Dagger for instance). It's biggest drawback is that it requires the developers to be disciplined in following that. Such a discipline is the result of their understanding of design patterns and their inherent passion to follow them. This can be taken for granted for companies like Google, but is far from the IT industry average.

Sunday, May 17, 2015

Using Spring DI to break dependency injection pattern

No doubt, Spring is a flexible framework for building web apps, but in some cases more flexible than it should be! In this article I focus on Spring DI, the dependency injection framework and the ability it gives you to break the idea behind the dependency injection pattern.

To expose the issue, I use the famous message-printer toy app, with Spring v4.1.6.RELEASE, orchestrated by spring-boot v1.2.3.RELEASE. The code I use in this post can be found on github.

Domain Modelling


Let's say we have a  MessageService interface and two dummy domain class implementations, MessagePrinterImpl1, MessagePrinterImpl2 as shown:


Controller


We will need also a dummy controller that maps every HTTP request to a method that just logs the message in the console.

And of course a main method to run the app.
Run the app with maven or gradle:
- maven:  mvn spring-boot:run
- gradle:  ./gradlew bootRun

Visit http://localhost:8080 and you get the following log in your console which verifies that an MessagePrinterImpl1 object was injected as a MessageService:

What is wrong


Let's explain the Spring DI magic that happens here.
PrinterController has a field of type MessageService that needs to be injected. Since there are two MessageService implementations in the classpath, Spring DI will need a way to decide which one to inject. One way to do this is the @Resource(name = "impl1") annotation, which asks for the bean named "impl1" to be injected. Spring will search in the application context to find a bean named "impl1" which is of type MessageService. As we have annotated MessagePrinterImpl1 with @Component(value = "impl1"), an instance of this class will be injected.

In short, what we have achieved is to couple the PrinterController class with a concrete implementation of MessageService and we did that by using dependency injection... But hold on a sec, the goal of dependency injection pattern is to decouple code, directly the opposite than what we have done.

Solution


In order to use DI pattern for all the good reasons it was invented, you need to write a Config class that will bind interfaces to concrete implementations. By the way this is very similar with Guice Modules (thank God, Spring got rid of ugly xml config files!).

It is important that the @Bean annotation names the instantiated bean with service, as this is the name of the field we want to inject to. Alternatively, one can rename the method provider to service. This way, we enforce a clear separation between the business logic (PrinterController) and the instantiation of object graph (PrinterConfig). Testing this app is then made easy by providing a different Config class which binds MessageService to a mock implementation.

Conclusion


The cause of the problem is that Spring DI annotations are so flexible that even allow you to break the dependency injection idea.The lesson to be learned is to use this flexibility with caution. As Spring does not necessarily enforce the developer to follow the spirit besides the format of design patterns, it's the developer's responsibility to enforce them.