måndag 7 maj 2012

Using implicit parameters for Dependency Injection in Scala

A few days ago I made a post about some issues I have with the cake pattern for dependency injection. I want to illustrate a means of doing DI using scala's implicit parameters which retain the benefits of the cake pattern, but is more consice. The main benefit I see with the cake pattern is it's type safety. If we do something wrong the compiler will tell us, so we don't have to wait until we actually deploy to find out if our configuration is correct.

In order to understand how to do DI with implicit parameters we need to understand how implicit parametrs are resolved in Scala. In essence if we define a method with an implicit parameter:
When the compiler finds a call to a method with an implicit parameter it searches for a implicit val/var/def/object that provide an instance of a matching type. In this case I defined method that take a string as an implicit parameter. When I tried to call it without having an implicit value of type String in scope I got an error. Then specified an implicit val, and calling the method now prints the value of that val. We can however override this behaviour by providing the method with an argument explicitly such as:
For more information on how implicit parameters work and are resolved in Scala there are some excellent short blog posts on Daily Scala about it:
  1. http://daily-scala.blogspot.se/2010/04/companion-object-implicits.html
  2. http://daily-scala.blogspot.se/2010/04/implicit-parameters.html
  3. http://daily-scala.blogspot.se/2010/04/implicit-parameter-resolution.html

From the last post the resolution rules for implicits is summarized as:
There are very strict rules for which implicit value is to be applied to a implicit parameter. A simple way to think about it is that the "closest" definition will be used. Local scope, enclosing class, parent class, companion object of the desired type.
With this knowledge in our minds let's explore how we can use implicit parameters for dependency injection. For comparison I will show the same service/dao setup as in my previous post.
Since an implicit parameter can be provided explicitly it is trivial to mock the FooDao when testing the FooServiceImpl. I think this is perhaps the main advantage of using DI. For comparison, using this means of dependency injection the code is succint and not poluted with alot of boilerplate (12 LoC compared to 25 LoC using the cake pattern). One issue still remains. How do we ensure that FooDao is injected into the FooServiceImpl?
The main difference between the two approaches above is that if we extend Conf in our class in order to get the dependencies we need then we will have several Conf instances around and all of them will contain a fooService and a fooDao. So I think the former approach is preferable for this reason.

Another thing to notice is that in the Conf trait I have not explicitly provided FooServiceImpl with a FooDao when it is instantiated. Instead the compiler will resolve it for us using the locally defined fooDao val. Using this pattern we avoid having to spread a bunch of implicit val/def/var/object in our code. We have one central place where our configuration of the app is performed. If we make a mistake, such as defining two implicits with the same type in our conf so that the compiler don't know which to pick, we get a compiler error. Sweet!

But, wait. What if we have a circular dependency? First, try to avoid circular dependencies. Second, we could resolve it by passing a factory function to the class:
Then in our configuration do something like:
Jonas Bonér has already described this pattern in his blog post about different approaches to dependency injection. However, he states a thing I quite do not get:
This approach is simple and straight-forward. But I don’t really like that the actual wiring (importing the implicit declarations) is scattered and tangled with the application code.
This is obviously true if we choose to import the implicit definitions everywhere that we instantiate the classes. However, by using Conf as a factory for our dependencies we avoid having to import the implicits everywhere when we want a new instance of a certain "top level" class.

söndag 6 maj 2012

Problems with the Scala Cake Pattern - aka. Too much cake

A popular way to do dependency injection in Scala is to use the Cake pattern (see Jonas Boner's excellent blogg post about it). This pattern involves specifying components using traits and specifying dependencies by using self-types. My main problem with the cake pattern is that it is very verbose. To illustrate let's look at how we can use dependency injection in Java using Spring:
This is 20 lines of code for a FooService that depends on a FooDao. To get this to work we would also need a few lines of XML configuration to enable component scanning etc.

If we instead use the cake pattern we get the following.

This version is 25 lines of code. Sure, a separate xml file for the wireing is no longer necessary, we can just do: But, the problem with the verbosity still remains. The java sample consist of 20 lines whereas the scala code is 25. I believe most developer would agree that Java is a very verbose language, despite this it is still more concise than the scala equivalent! That should ring an alarm bell. If we instead of java decided to use scala in the annotation driven way then we could shrink those 20 lines even further. While this might be ok if the proportions in LOC shifted when adding more components, but it does not. As we add more and more components the boilerplate necessary will further increase the difference!

Of course LOC is not the whole story. We should also ask ourselves about the readability of the code. I have been using Spring quite a bit at work so my opinion is obviously biased because of it and I have not written alot of code using the cake pattern, but I think that the java/spring version is clearer. Also, you would likely end up having to specify all the vals and methods as protected in case you do not want to expose all the parts of the final component.

To summarize the Cake pattern makes our code verbose and (to me) hard to read due to the boilerplate necessary. I also see some other minor problems with the pattern, but my main concern is that it adds a lot of noise to the code base.

Should we just ditch the cake pattern and revert to using a DI framework like Spring? No. At least, I do not think so. Spring brings with it a bunch of fantastic features, but DI in Scala can be solved in a clean manner using some other language features. I will make a post about it next.