Pro Yearly is on sale from $80 to $50! »

DI with Kotlin

DI with Kotlin

In this talk, I am overviewing methods to achieve DI with Kotlin. There seems no de facto standard yet, and here I am discussing 3 possible ways. It's shown each method has its pros and cons respectively.

Reference
- Inversion of Control Containers and the Dependency Injection pattern
http://martinfowler.com/articles/injection.html
- SalomonBrys/Kodein: Painless Kotlin Dependency Injection
https://github.com/SalomonBrys/Kodein
- KotlinでもMinimal Cake Pattern - Qiita
http://qiita.com/rabitarochan/items/c6709a3a2e2f5d36d4e2
- Scalaにおける最適なDependency Injectionの方法を考察する 〜なぜドワンゴアカウントシステムの生産性は高いのか〜 - Qiita
http://qiita.com/pab_tech/items/1c0bdbc8a61949891f1f

979d93b360f80486b121486a9d063ad5?s=128

Hiroshi Kurokawa

July 05, 2016
Tweet

Transcript

  1. DI WITH KOTLIN KOTLIN MEETUP #1 2016.07.05 Hiroshi Kurokawa (@hydrakecat)

  2. WHAT’S DI? ▸ Dependency Injection ▸ Client takes advantage of

    a Service ▸ Injector provides a concrete implementation of the Service to the Client Client Service ServiceImpl
  3. WHAT’S DI? ▸ Dependency Injection ▸ Client takes advantage of

    a Service ▸ Injector provides a concrete implementation of the Service to the Client Client Service ServiceImpl
  4. WHAT’S DI? ▸ Dependency Injection ▸ Client takes advantage of

    a Service ▸ Injector provides a concrete implementation of the Service to the Client Client Service ServiceImpl Injector
  5. WHAT’S DI? ▸ Dependency Injection ▸ Client takes advantage of

    a Service ▸ Injector provides a concrete implementation of the Service to the Client Client Service ServiceImpl Injector
  6. ADVANTAGES ▸ Decoupling of components ▸ Model layer doesn’t need

    to know about infrastructure layers ▸ Less boilerplates ▸ Configurable ▸ Unit Testing ▸ Production/Development Release
  7. 3 APPROACHES TO ACHIEVE DI WITH JAVA ▸ DI Container

    ▸ Constructor ▸ Setter (See http://martinfowler.com/articles/injection.html)
  8. 4 APPROACHES TO ACHIEVE DI WITH KOTLIN ▸ DI Container

    ▸ Constructor ▸ Setter ▸ Interface with default implementation
  9. ▸ DI Container ▸ Constructor ▸ Setter ▸ Interface with

    default implementation 4 APPROACHES TO ACHIEVE DI WITH KOTLIN
  10. 1. Java DI Container ▸ Spring ▸ Dagger 1&2 ▸

    so on … 2. Kotlin DI Container ‣ Injekt ‣ Kodein 3. Interface with default implementation 3 WAYS TO DO DI
  11. 1. JAVA DI CONTAINER ▸ Spring ▸ Guice ▸ Dagger

    1 & 2
 needs annotation processor (kapt) @Component(modules = arrayOf(DripCoffeeModule::class) ) interface CoffeeShop { fun maker() : CoffeeMaker } class CoffeeMaker { @Inject lateinit var heater: Heater @Inject lateinit var pump: Pump }
  12. 1. JAVA DI CONTAINER ▸ Pros ▸ Based on JSR-330

    ▸ Many frameworks ▸ Cons ▸ Kapt is not stable yet ▸ Compile/runtime error can be complicated ▸ Interoperation with Java might be required
  13. 2. KOTLIN DI CONTAINER class CoffeeMaker() { val injector =

    Injector() private val heater: Heater by injector.instance() private val pump: Pump by injector.instance() … } ‣ In Kotlin, you can delegate getter of properties
  14. ‣ Kodein 1. Describe dependencies val dripCoffee = Kodein {

    bind<Heater>() with provider { ElectricHeater() } bind<Thermosiphon>() with provider { Thermosiphon(instance()) } bind<Pump>() with provider { instance<Thermosiphon>() } } 2. KOTLIN DI CONTAINER
  15. class CoffeeMaker() { val injector = KodeinInjector() private val heater:

    Heater by injector.instance() private val pump: Pump by injector.instance() … } fun main(args: Array<String>) { val maker = CoffeeMaker() maker.injector.inject(dripCoffee) maker.brew() } ‣ Kodein 1. Describe dependencies 2. Delegate to KodeinInjector 2. KOTLIN DI CONTAINER
  16. ▸ Pros ▸ Factory can be used to provide a

    service! ▸ It’s hard with Java apt-based DI container ▸ Pure Kotlin ▸ Cons ▸ Possible runtime error ▸ Configuration could be cumbersome especially when dependencies are nested 2. KOTLIN DI CONTAINER
  17. 3. INTERFACE ▸ In Kotlin, interface can have default implementations

    ▸ By extending an interface, client can have an access to a service implementation ▸ “Minimal Cake Pattern” in Scala could be a good guide interface UsesCoffeeModule { val coffeeModule: CoffeeModule } interface MixInDripCoffee : UsesCoffeeModule { override val coffeeModule: CoffeeModule get() = DripCoffee() }
  18. 3. INTERFACE interface CoffeeMaker: UsesCoffeeModule { fun brew() { coffeeModule.heater().on()

    coffeeModule.pump().on() coffeeModule.pump().off() coffeeModule.heater().off() } } fun main(args: Array<String>) { // With MixInDripCoffee interface, a DripCoffee is injected val maker = object : CoffeeMaker, MixInDripCoffee {} maker.brew()
  19. 3. INTERFACE ▸ Pros ▸ No configuration DSL ▸ Dependency

    is clear in the code ▸ No complicated runtime/compilation error ▸ Cons ▸ Not so flexible to configure
  20. CONCLUSION ▸ There seems no de facto standard DI method

    in Kotlin yet ▸ Java DI container is probably the best choice for now ▸ If you’re willing to struggle with Kapt ;-) ▸ Minimal Cake Pattern would be great if you don’t need much flexible configuration
  21. Thank you! Hiroshi Kurokawa (ࠇ઒ ༸) @hydrakecat https://github.com/hkurokawa https://speakerdeck.com/hkurokawa hydrakecat.hatenablog.jp