Advocating for and against Koin

Yev Kanivets
The Kotlin Chronicle
5 min readMar 19, 2019

With introduction of Kotlin as official language for Android development at Google I/O 2017, we have seen the exponential rise of its adoption within community. Such an interest to new language isn’t surprise as Kotlin provides number of new and handy syntax constructions, which make Android developers even more happy.

But not only Android applications took a benefit from the new language. Right now almost all well-known and widely-adopted libraries written in Java have been migrated to Kotlin or their functionality has been mimicked by Kotlin idiomatic ones.

And there is a question — which libraries should we use now? The answer — it depends. Let’s consider two popular libraries for Dependency InjectionsDagger and Koin.

Why do Dependency Injection?

When you are putting your fingers on keyboard to write the code for first time in your life you, for sure, don’t think and even don’t know of such an abstract thing as “Dependency Injection”.

But as you grow as developer, so your applications do. With time and experience you start to notice that some things are too coupled or too buried into other things. The good OOP design requires small (almost) independent classes, which are responsible for one well-defined thing.

Such small classes need to be assembled into working “something” somehow. The first idea is to create them where they are needed for first time and then use. Such approach is OK, but resembles to building car details right inside the car, which obviously isn’t the most convenient way :)

At the factory all vehicle parts are built separately and then injected into bigger ones and those are injected into even bigger ones and so on. This injection of smaller parts into bigger parts in programming is called Dependency Injection. It’s a convenient way to deal with a system complexity.

How do Dependency Injection?

The most common mistake I’ve seen among developers is to directly associate some library for Dependency Injection with the Dependency Injection pattern itself. There are dozens of Java and Kotlin libraries, which allow you to build Dependency Graph: Dagger, Koin, Kodein and so on.

The truth is that at first you need to implement Dependency Injection with your own hands to fully understand how it works and why you need it (or don’t). Then you can choose any library you want to simplify the process or write your own solution if you want.

What the Dagger is?

Dependency Injection is the very common technique and the very common problem from other side. So a long time ago every company was implementing their own solution and kept it private.

But the hero came… :) Square contributed to Android Development enormously by creating many open source tools for common programming problems. One of them was Daggercompile-time, annotation-driven, fast dependency injector.

The second version of Dagger is now supported officially by Google, which is the big advantage for any library. It’s a robust, stable and convenient way to inject your dependency.

But it was written in Java to be used in apps written in Java by Java developers. So I would say it’s Java centric. Dagger 2 is powered by generated classes created at compile time from special annotated by developers interfaces. And it doesn’t benefit from Kotlin new stuff, which clearly shows the opportunity for new Dependency Injection libraries.

What the Koin is?

Writing Dependency Injector in Kotlin is relatively easy task mostly thanks to reified classes in conjunction with inline functions, which gives you information about generic’s real class in Runtime (works only with Kotlin).

There even was a challenge at Kt. Academy, the goal of which was to write your own Dependency Injector with Kotlin. I was too busy that week, but you can take a look on others participants projects, which are very and very interesting.

But there are few most popular libraries for Dependency Injection written in Kotlin, one of which is Koin.

A pragmatic lightweight dependency injection framework for Kotlin developers. Written in pure Kotlin, using functional resolution only: no proxy, no code generation, no reflection.

Everything written on official GitHub page is true. It’s really lightweight, so to start using Koin on Android you need the only one dependency, which is:

implementation “org.koin:koin-android:$1.0.2”

It’s really the Dependency Injection framework, so you can build your Dependency Graph as easy as this:

// Given some classes 
class Controller(val service : BusinessService)
class BusinessService()
// just declare it
val myModule = module {
single { Controller(get()) }
single { BusinessService() }
}

As you could see from previous code block there is beautiful idiomatic DSL (domain specific language), which allows you write the code, which can be understood even by not-developers.

Finally, no such things as proxy, code generation and reflection exist in open source codebase. So everything looks perfect and it seems that we must throw away good old Dagger at first glance.

But wait, let’s just give it a try…

The story began at the moment when our mobile team (which I’m proud to be part of) at 360Learning considered the possibility to integrate Dependency Injection 3rd party into our Android app. We are very serious about adding any 3rd party, so we tried several options on one of our modules.

At first I was happy with Koin as its integration happened almost seamlessly: add dependency, move Dependency Graph creation to Koin module and refactor it to use Koin’s methods.

But then I’ve noticed that I can inject dependencies with get() function even without declaring anything to satisfy it and, even worse, if I need to pass some parameters into dependency I need to use parametersOf() which just takes varargs.

It means that as developer you have no hints and no checks on any parameters you pass. You need to go to Koin module to see expected parameters and then thoroughly paste them in right order and in right quantity into parametersOf().

And, of course, there are no compile-time checks on that dependencies, so you will obtain the runtime crash only at moment of first use of any of unsatisfied dependency.

Conclusion

With a team even of few people it’s challenging task to not forget to change dependency injection in Koin module and across the app once original dependency constructor changed. So the risk to break application in production seems to be too high price for handy idiomatic Kotlin syntax. At least for our team…

References

--

--

Yev Kanivets
The Kotlin Chronicle

Technical Lead Mobile @ 360Learning | KMP enthusiast | Husband & dad | Marathon finisher