My favorite ways of injecting dependencies in Scala
The following post is a shorter version of a post I’ve published on my former blog, Coffeebean. In this article, we will focus on dependency injection with only pure Scala code (no framework involved), resolved at compile time.
There are many ways to inject dependencies in Scala, this are my current favorite ways of doing it.
The “piece of cake” pattern
In our example, we have a Play app with a controller. But this kind of wiring would work with any Scala application.
We provide a route to find Internet links from a query string. To achieve this we will rely on the DuckDuckGO API. But for tests we would like to mock this service. As we want to be able to test our controllers, we need to be able to inject our service into the controller. To add a little more fun, the link service depends on a logging service.
The first thing to do is to define a ServicesComponent trait. This trait will embed our services :
Now the controller can extend this trait to get dependencies from it :
this : ServicesComponent => in the ApplicationController trait means that we need to extend ServicesComponent when we instantiate an ApplicationController, to retrieve dependencies.
This notation is called Self Type or Self Reference.
Play uses objects (by default) to wire routes to controllers. This is part of the Scala world goodness, there is no need to rely on containers like Servlet/Java EE ones. As you can manage your controller objects yourself, you can do whatever you need to contruct them. At the end of the sample code above, we create the Application instance that will embed the services by extension of the ServicesComponent trait.
You can see this as a very light and flatten variation of the cake pattern, or a “Piece of Cake Pattern”! The cake pattern is often accused of getting too big too fast and being hard to manage. But here, I only use the power of Scala self types with one layer, and traits only where they are needed. Every dependency is wired inside the ServicesComponent trait.
If we want to wire another version of a service, for example for tests, we just need to extend the ServicesComponent trait and override the value :
Simple, isn’t it?
Alternative method : use a simple constructor
You can also use a simple constructor instead of the self type. As Alex N. pointed out in the comments, it can be useful if you want a single instance of your service component, that can be accessed from anywhere (for example to start/stop services at application startup/shutdown). Here again, as you can manage your controller objects yourself (no container), you can do whatever you need to contruct them.
With this method, your controller trait is now a class :
Wiring is still very simple :
Finally, you can test your controller with a MockServices object :
And you, what’s your favorite way of injecting dependencies in Scala?