Dependency Injection in Scala - cake pattern
Tags: scala, di, functional, programming
Published: 2023-02-18 13:55:15

---
title: Dependency Injection in Scala - cake pattern
published: true
description: a tour on dependency injection basics in scala, and explanation how to do it using the cake pattern
tags: scala, di, functional, programming
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-01-03 18:44 +0000
---

In this post we'll cover Dependency Injection (DI) basics in scala, and focus on how to perform it manually with using the `cake pattern`.
All code examples are [available on github](https://github.com/mklabs-io/scala-dependency-injection).
 
## Introduction to DI

Dependency injection encourages loose coupling. It tells you that this is wrong:

```scala

class MyRepository

class BlueService {
  val a = new MyRepository() 
}

```

and rather encourages you to instead do:
```scala
class MyRepository
class BlueService(a: MyRepository) {}
```
With this change we're defining explicitly which dependencies the `MyService` constructor needs, and that those should be <i>injected</i> from outside. The rule of thumb: if you see the `new` keyword inside a service, that should immediately yield a red flag in your head.


Might not seem much, but this is already a big improvement, as it greatly simplifies the way we can build tests for the `MyService` class.

Let's do that. So let's start by defining our dependencies (no pun intended) in `build.sbt`:
```scala
libraryDependencies ++= Seq(
  "org.scalamock" %% "scalamock" % "5.2.0" % Test,
  "org.scalatest" %% "scalatest" % "3.2.14" % Test
)

```
And here a sample layout for our mocking:

```scala
import eu.m6r.scalalightningtalks.di.Background.DI2.{BlueService, MyRepository}
import org.scalamock.scalatest.MockFactory
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.must.Matchers

class BackgroundTest extends AnyFlatSpec with Matchers with MockFactory {

  it should "test something BlueService when repository behaves a certain way" in {
    val mockRepository = mock[MyRepository]
    // service under test
    val sut = new BlueService(mockRepository)
    // ...
  }

}

```
And this way we can easily manipulate the response from MyRepository. If our original implementation was:
```scala
    class MyRepository {
      def findOne(): String = "one"
    }
    class BlueService(a: MyRepository) {
      def get(): String = a.findOne()
    }

```
.. then we could mock the response, for example, as such:

```scala
  it should "test something BlueService when repository behaves a certain way" in {
    val mockRepository = mock[MyRepository]
    // service under test
    val sut = new BlueService(mockRepository)
    // mock
    (mockRepository.findOne _)
      .expects()
      .returning("two")
      .once()
    sut.get() shouldBe "two"

  }

```


However, we're not done yet; consider the following: 

```scala
trait Repository
class MyRepository extends Repository

class BlueService(a: Repository) {}

```

By defining a general contract for the `Repository` (via our trait), we are nicely adding a **separation of concerns** - in the future we can easily swap to a different concrete `Repository` implementation (for example, instead using a given DB, using another), without having to change anything in `BlueService` implementation.


If this is your first time hearing about it, you may be asking yourself: <i> But where then do I instantiate and pass the concrete Repository instance?</i? 
In other words: Where do I instantiate and <i>inject</i> `BlueService` dependency?

DI relies on Inversion of Control (IoC) principle, which encourages one to create the concrete service implementations outside of the actual services that use them. This is usually done in a central container, or spread out across multiple centralization containers which determine which dependency is instantiated and gets injected to which class. 
  

## Options for DI in Scala

We have several options for DI in Scala:
- using libraries from java world, such as [Guice](https://github.com/google/guice);
- using pure scala: manually injecting via a central container, with the `cake pattern`, or with the `reader monad`;
- using scala libraries: [MacWire](), [SubCut](https://github.com/dickwall/subcut), [Scaldi](https://github.com/scaldi/scaldi)

In this post we'll just show case the most basic form of manual DI, and then exemplify the second alternative with the `cake pattern`.



## Manual DI - central container

Let's start with the simplest, and arguably the most frowned upon. If we're being honest here, quite a reasonable one if you're working on a small project.

Just create a main container where your configuration(s) is/are loaded, and passed to create dependencies, and inject them in several services.

```scala

trait Repository
class MyRepository extends Repository
class BlueService(repository: Repository)
class GreenService(repository: Repository)

object {
   val myRepo = new MyRepository()
   val blueService = new BlueService(myRepo)
   val greenService = new GreenService(myRepo)
}

```
The beauty about this solution is two-folded: one it is very simple - it is straight forward, anyone can understand it, there is no magic happening underneath the hood. The second is that we have compile type safety giving us compile time seat-belt for any mistakes.

This has one core drawback, which is that it is not very scalable. It requires tediously declaring all new dependencies, increasing linearly as the project grows, while making sure that the exact instantiation and injection are guaranteed at the right time and place. Eventually we might bump into one of these mistakes:

```scala
object {
   val blueService = new BlueService(myRepo)
   val myRepo = new MyRepository()
}
```
.. and be sure that this will compile, but `myRepo` will be `null` when referenced, since it hasn't been initialized (a case of forward reference). 

Arguably not the worst thing in the world, and easily solvable by letting the compiler solve it for us with the keyword `lazy`:
```scala
object {
   lazy val blueService = new BlueService(myRepo)
   lazy val myRepo = new MyRepository()
}
```

However not all is bad; in fact, manual DI does not get nearly as much love as it should. In comparison with most DI frameworks, which use reflection at run-time to dynamically infer the dependency graph, it gives us type-safety at compile time, a slight startup time improvement, and, most of all, removes the magic done behind the scenes. I can't state this enough: no framework magic to fight against (looking at you spring).



## Manual DI - Cake pattern

The key building block to implement the cake pattern is to relie on trait `mix-in` instead of inheritance. 
The name `cake` comes from the idea of multiple layers - as we mix-in multiple traits with each other. 
We will dive right next in how the mix-in mumbo jumbo is executed - but just keep in mind that this is how one hooks dependencies, which forces the implementer of the traits to then inject concrete definitions of them. 

Let's review some fundamentals about scala traits to make the previous paragraph make any sense.



### cake pattern background: traits & diamond problem

The closest thing to a trait in the java world would be an interfaces - more concretely a java 8+ interface. Since java 8, interfaces can even have concrete method implementation using the `default` keyword, and so can traits. One interface can also, like scala traits, extend more than one interface:

```java

interface Demo1 {}

interface Demo2 {}

// this is fine
interface Demo3 extends Demo1, Demo2 {}

``` 
This might ring some alarm bells and cold sweats in you, namely regarding the [diamond problem](https://www.tutorialspoint.com/what-is-diamond-problem-in-case-of-multiple-inheritance-in-java).

The problem comes when the original interfaces being extended share one or more methods with the same signature: 

```java
    private interface Demo1 {
        default String greet() {
            return "hello";
        }
    }

    private interface Demo2 {
        default String greet() {
            return "hallo";
        }
    }

    // interface can extend multiple interfaces, 
    // however on conflict, one will need to override

    private interface Demo3 extends Demo1, Demo2 {
        @Override
        default String greet() {
            return Demo1.super.greet();
        }
    }

```

The way java handles this situation is by forcing the developer to explicitly implement the concrete method in conflict - the `greet` method in our silly example.


Like java interfaces, one can extend a trait with another trait:

```scala
trait FileReader
trait OsFileLocker
// this is also valid syntax:
trait FileWriter extends FileReader with OsFileLocker  
```

However, in presence of conflicting method signatures, scala will behave differently. Here are more complete illustration of the diamond problem: 

```scala
    
    trait FileOps {
      def readFile: String
    }

    trait FileReader extends FileOps {
      override def readFile: String = "loaded"
    }

    trait OsFileLocker extends FileOps {
      override def readFile: String = "lock created & file loaded"
    }

    class FileSystemConsumer extends FileReader with OsFileLocker


```
Note: extending in Scala 3 is, in my opinion, clearer: `class FileSystemOperator extends FileWriter, OsFileLocker`

The scala compiler will allow such wiring and apply a simple disambiguation rule: on conflicting method signature, use the implementation of the <i>last trait</i> being extended, e.g. the one one furthest to the right (`OsFileLocker`).

```scala
println(new FileSystemConsumer().readFile)
// will print: lock created & file loaded
```

To make it perfectly clear, if one swapped the order, the print message would simply be "loaded":

```scala
    class FileSystemConsumer extends OsFileLocker with FileReader
    println(new FileSystemConsumer().readFile)
    // will print: loaded
``` 




### cake pattern background: self type annotation

The second essential trick we'll be using is scala's [`self` type](https://docs.scala-lang.org/tour/self-types.html) - which provides a way to mix-in another trait: 

```scala
  trait Greeting {
    def intro: String
  }
  

  trait Greeter {
    this: Greeting =>
    def greet: String = s"$intro, I am Foo"
  }

```
By specifying `this: Greeting =>` we are defining that whoever extends `Greeter` will need to also extend the `Greeter` trait, or <i>anything that extends it</i>.  The <i>anything that extends it</i> is the relevant part, and the main reason why we don't simply declare `trait Greeter extends Greeting`.

If one tried to instantiate a Greeter trait, the compiler would immediately complain:

```scala
// this won't compile
val greeter = new Greeter
``` 
But if one would define a concrete implementation, for example:

```scala

  trait PortugueseGreeting extends Greeting {
    override def intro: String = "Olá"
  }
```

Then the following would compile:

```scala
    val greeter = new Greeter with PortugueseGreeting
    println(greeter.greet)
    // will print: Olá, I am Foo
```
The key part here to understand is the `with PortugueseGreeting` - the concrete part where we're injecting the intended concrete implementation of the `Greeting` contract. One would not be able to force the developer to inject a concrete implementation if one would have used inheritance to define the `Greeter` trait:

```scala
    // bad: using inheritance
    trait Greeter with Greeting {
      def greet: String = s"$intro, I am Foo"
    }
```

Note that anything available in the `Greeting` trait will also be available for the `Greeter` trait - in our silly example the `intro` method - when using the preferred mix-in implementation.



### the cake pattern example (finally)

We are going to use an example often seen in API's code, namely where we want to specify that a service (where business logic resides) needs to be injected with a generic implementation of a repository (where we define CRUD operations with a given data store).

Let's keep this simple; our model:
```scala
  case class User(id: Long, name: String)
```
And our generic UserRepository contract:

```scala
    trait UserRepository {
      def findOne(): User
    }
```
The second step is where specific cake pattern design would kick in. One would define a component, say `UserRepositoryComponent`:

```scala
  trait UserRepositoryComponent {
    // expose the generic contract
    val userRepo: UserRepository
  }
```
`Components` have a single purpose: to expose a given contract. Given the property that we talked earlier that the exposed value - `userRepo` in our example - will be available for use in the trait where any other trait where it is mixed-in.
So if we had a generic service contract:
```scala
    trait UserService {
      def findUser: User
    }

```

We could wire all of these together in a `UserServiceComponent`:
 
```scala
  trait UserServiceComponent {
    this: UserRepositoryComponent =>

    val userService: UserService = new MyUserService

    class MyUserService extends UserService {
      def findUser: User = userRepo.findOne()
    }

  }

```
I hope by now the reason for the name `cake` starts becoming clearer. Like a cake with several layers, our component declares a class inside of it, which, in turn, makes use of the `userRepo` value thanks to the `this: UserRepositoryComponent =>` mix-in.

At this point we're exactly in the same situation as we were when we couldn't instantiate a new `Greeter` instance, since we still can't instantiate a `UserServiceComponent`. No worries, let's implement a concrete mock Repository:

```scala
  trait CassandraUserRepositoryComponent extends UserRepositoryComponent {
    val userRepo = new CassandraUserRepository

    class CassandraUserRepository extends UserRepository {
      def findOne(): User = User(1L, "john")
    }
  }

```

Now we can glue it all together:

```scala

    val userServiceComponent = new UserServiceComponent with CassandraUserRepositoryComponent
  println(userServiceComponent.userService.findUser)
  // will print: User(1,john)

```
Just like before, we're leveraging scala self-type to inject the concrete implementation of our repository <i>only</i> on instantiation.


## Conclusion

In this post we went through the basics of dependency injection with examples in scala, and dived into a concrete way to wire your code to perform DI manually, with the cake pattern. As mentioned in the beginning, feel free to grab the code snippets available [on github](https://github.com/mklabs-io/scala-dependency-injection) to play with them.

We sincerely hope that we were able to distill all building blocks of the cake pattern in simple terms that didn't require you to take a PhD in category theory.


  
## References

- [Scala `self` types](https://docs.scala-lang.org/tour/self-types.html)
- [Really old, but great post about the Cake Pattern by industry heavy weight Jonas Bonér, CTO at Lightbend](http://jonasboner.com/real-world-scala-dependency-injection-di/)
- [Blog post distilling all required building blocks in Scala for using the Cake pattern](https://medium.com/rahasak/scala-cake-pattern-e0cd894dae4e)
- [A fabulous deep dive to DI in scala from the creator himself of the `MacWire` library, Adam Warski](http://di-in-scala.github.io/)
- [Scala Mock quickstart](http://scalamock.org/quick-start/)
- [Scala test with Mock documentation](https://www.scalatest.org/user_guide/testing_with_mock_objects)