Dependency Injection with Koin


What is dependency injection

Dependency injection is a technique to organize dependencies of services at runtime. If you have a really large application you may have encountered the problem of passing some objects down the whole stack and maybe using singletons and static method to overcome this.

But these are hard to substitute in Tests. Though to avoid this we let a framework organize these dependency issues for us. See Wikipedia.

You may know dependency injection from some popular frameworks like Spring or Angular.

Terms of dependency injections

In order to understand the following paragraphs I will explain some common vocabulary of dependency injection.

Module

A module is somewhat a container for your dependency graph. It contains all objects known to the dependency injection context.

To separate dependency injection contexts you can create multiple modules.

Component

A component is the element that requests and receives the dependencies from the framework.

Getting started with Koin

Koin lets you organize your dependencies in a functional Kotlin native style.

fun myModule() = module {
    single() { DataBaseConnector() }
    single() { WebService() }
}

This declares a module with a DataBaseConnector and a WebService as Singletons.

To get started with injection you can simply call startKoin with a list of modules as parameter.

fun main(args: Array<String>) {
  startKoin(listOf(myModule())
  stopKoin()
}

Between startKoin and stopKoin we can leverage the dependency injection framework.

fun main(args: Array<String>) {
  startKoin(listOf(myModule())
  MyComponent()
  stopKoin()
}

MyComponent is a component which will receive the dependencies.

To access them in the class we use the delegate feature by inject() of Kotlin.

class MyComponent() : KoinComponent {
    private val dataBaseConnector by inject<DataBaseConnector>()
    private val webService by inject<WebService>()

    init {
      // Get the data from the database
      dataBaseConnector.getRows().let {
        // Display the data with the webService
        webService.serve(it)
      }
    }
}

Comparison to Dagger

Pros

The main advantage over the Dagger framework in my eyes is, that you don’t need code generation and therefore a simpler buildprocess.

Koin leverages more of Kotlins features and solves dependency injection in a functional style that is pretty concise.

Dagger has the advantage of not defining the dependency tree by hand. You can just annotate all your classes with @Inject and @Singleton and dagger resolves this for you. But the extra effort you have in Koin is definitely worth just because you get a cleaner dependency notation all in one place.

Cons

A major drawback of Koin in my eyes is the Logger. It has no SLF4J binding and has to be implemented by hand. Koin has some arbitrary KoinLogger for all internal logs. Apart from this I have found the logger quite useful at debugging dependency problems.