Slide 1

Slide 1 text

@HandstandSam #AndroidSummit DIY Dependency Injection with Kotlin Sam Edwards -

Slide 2

Slide 2 text

@HandstandSam #AndroidSummit Why am I up here talking about this? ! Demystify the topic of Dependency Injection ! Show how you can implement DIY, if you choose

Slide 3

Slide 3 text

@HandstandSam #AndroidSummit Our Team’s Story ! Got tasked to build a reusable SDK ! This was the first time we were building a complex SDK

Slide 4

Slide 4 text

@HandstandSam #AndroidSummit Product Requirements ! SDK will be used by different apps, in different codebases ! Should not assume clients will be using a 3rd party library ! Stay lean and lightweight ! Make the SDK configurable

Slide 5

Slide 5 text

@HandstandSam #AndroidSummit Technical Requirements ! Reactive Programming ! Immutable Data ! Modular Code ! Single Responsibility Code ! Well Tested Code ! Avoid 3rd Party Libraries ! 100% Kotlin ! Dependency Injection

Slide 6

Slide 6 text

@HandstandSam #AndroidSummit Why 100% Kotlin?

Slide 7

Slide 7 text

@HandstandSam #AndroidSummit Why 100% Kotlin? makes coding easy and concise.

Slide 8

Slide 8 text

@HandstandSam #AndroidSummit Why 100% Kotlin? makes dependency injection easy and concise.

Slide 9

Slide 9 text

@HandstandSam #AndroidSummit Kotlin Language Features makes DIY Do-able ! Named Parameters ! Default Parameters ! “by lazy” ! () -> lambdas

Slide 10

Slide 10 text

@HandstandSam #AndroidSummit TL;DR - The DIY Recipe ! Kotlin ✅ ! Constructor Injection ✅ ! No Annotations or Code Generation ✅ ! Some Hacks for Activities & Fragments

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

@HandstandSam #AndroidSummit Why Dependency Injection? ! It enables all the really cool things I like to talk about

Slide 13

Slide 13 text

@HandstandSam #AndroidSummit It Enables Testing DevFest Florida

Slide 14

Slide 14 text

@HandstandSam #AndroidSummit It Enables Custom Debug Features Droidcon Boston

Slide 15

Slide 15 text

@HandstandSam #AndroidSummit It Enable Mock Flavors Droidcon NYC

Slide 16

Slide 16 text

@HandstandSam #AndroidSummit Dependency Injection is Not Magical

Slide 17

Slide 17 text

@HandstandSam #AndroidSummit Dependency Injection is Not Magical DI !=

Slide 18

Slide 18 text

@HandstandSam #AndroidSummit Dependency Injection is Use THIS instead of THAT. “Swapping”

Slide 19

Slide 19 text

@HandstandSam #AndroidSummit Dependency Injection is Passing in dependencies
 instead of pre-defining them. Inversion of Control

Slide 20

Slide 20 text

@HandstandSam #AndroidSummit Dependency Injection is Inversion of Control Code Dependency

Slide 21

Slide 21 text

@HandstandSam #AndroidSummit Dependency Injection is Inversion of Control Code Dependency Logger

Slide 22

Slide 22 text

@HandstandSam #AndroidSummit Dependency Injection is Inversion of Control Code AndroidLogger Logger

Slide 23

Slide 23 text

@HandstandSam #AndroidSummit Dependency Injection is Inversion of Control Code AndroidLogger SystemOutLogger or Logger

Slide 24

Slide 24 text

@HandstandSam #AndroidSummit Dependency Injection is Inversion of Control Code AndroidLogger SystemOutLogger or Logger

Slide 25

Slide 25 text

@HandstandSam #AndroidSummit Dependency Injection is Inversion of Control Code AndroidLogger SystemOutLogger or Logger “Inversion of Control" aka “Swapping”

Slide 26

Slide 26 text

@HandstandSam #AndroidSummit Avoid Static Instances - “new” is Your Friend Log.d("TAG", “message”) ! Global state ! Must be mutable to be “reset” between tests ! Hard to mock in tests - PowerMock

Slide 27

Slide 27 text

@HandstandSam #AndroidSummit No Dependency Injection class NoInjectionRepository { val log = AndroidLogger() val database = SqlDelightDatabase() fun updateUser(user: User) { log.log("Updating User: $user") database.save(user) } } NoInjectionRepository().updateUser(user)

Slide 28

Slide 28 text

@HandstandSam #AndroidSummit Common Types of Dependency Injection

Slide 29

Slide 29 text

@HandstandSam #AndroidSummit Setter Injection class SetterInjectionRepository { lateinit var log: Logger lateinit var database: Database fun updateUser(user: User) { log.log("Updating User: $user") database.save(user) } } val setterInjection = SetterInjectionRepository() setterInjection.log = AndroidLogger() setterInjection.database = SqlDelightDatabase()

Slide 30

Slide 30 text

@HandstandSam #AndroidSummit Constructor Injection class ConstructorInjectionRepository( val logger: Logger, val database: Database ) { fun updateUser(user: User) { log.log("Updating User: $user") database.save(user) } } ConstructorInjectionRepository( logger = AndroidLogger(), database = SqlDelightDatabase() )

Slide 31

Slide 31 text

@HandstandSam #AndroidSummit class ConstructorInjectionRepository( val log: Logger = AndroidLogger(), val database: Database ) { fun updateUser(user: User) { log.log("Updating User: $user") database.save(user) } } ConstructorInjectionRepository( database = SqlDelightDatabase() ) Why Constructor Injection is Great for Kotlin Default Parameters Named Parameters

Slide 32

Slide 32 text

@HandstandSam #AndroidSummit Why DIY Constructor Injection Makes Sense ! Compile Time Safety ! No 3rd party library ! No magic ! Easy to “Find Usages” and understand

Slide 33

Slide 33 text

@HandstandSam #AndroidSummit Aren’t Their Libraries That Do DI for You? ! Yes, let’s take a look.

Slide 34

Slide 34 text

@HandstandSam #AndroidSummit Open Source DI Libraries ! Dagger ! Toothpick ! Koin ! Kodein

Slide 35

Slide 35 text

@HandstandSam #AndroidSummit ! Dagger ! Toothpick ! Koin ! Kodein Code Generation YES YES NO NO

Slide 36

Slide 36 text

@HandstandSam #AndroidSummit ! Dagger ! Toothpick ! Koin ! Kodein Code Generation YES YES NO NO ❌ ❌

Slide 37

Slide 37 text

@HandstandSam #AndroidSummit ! Dagger ! Toothpick ! Koin ! Kodein Code Generation YES YES NO NO Single
 Instance NO NO YES NO ❌ ❌

Slide 38

Slide 38 text

@HandstandSam #AndroidSummit ! Dagger ! Toothpick ! Koin ! Kodein Code Generation YES YES NO NO Single
 Instance NO NO YES NO ❌ ❌ ❌

Slide 39

Slide 39 text

@HandstandSam #AndroidSummit ! Dagger ! Toothpick ! Koin ! Kodein Code Generation YES YES NO NO Single
 Instance NO NO YES NO Available
 at the time YES YES YES NO ❌ ❌ ❌

Slide 40

Slide 40 text

@HandstandSam #AndroidSummit ! Dagger ! Toothpick ! Koin ! Kodein Code Generation YES YES NO NO Single
 Instance NO NO YES NO Available
 at the time YES YES YES NO ❌ ❌ ❌ ❌

Slide 41

Slide 41 text

@HandstandSam #AndroidSummit ! Dagger ! Toothpick ! Koin ! Kodein Code Generation YES YES NO NO Single
 Instance NO NO YES NO Available
 at the time YES YES YES NO Adds dependency on another library YES YES YES YES ❌ ❌ ❌ ❌

Slide 42

Slide 42 text

@HandstandSam #AndroidSummit So, How Much Work is DIY? ! Not that much ! Slightly more verbose ! Have to manually build advanced DI features ! Great for most use cases when you don’t already know a DI library really well

Slide 43

Slide 43 text

@HandstandSam #AndroidSummit DIY Dependency Injection in Practice

Slide 44

Slide 44 text

@HandstandSam #AndroidSummit ShoppingApp - Open Source on GitHub https:/ /github.com/handstandsam/ShoppingApp

Slide 45

Slide 45 text

@HandstandSam #AndroidSummit Network Graph interface NetworkGraph { val categoryRepo: CategoryRepo val itemRepo: ItemRepo val userRepo: UserRepo }

Slide 46

Slide 46 text

@HandstandSam #AndroidSummit Create Graphs of Dependencies • Similar to Dagger @Component OkHttpClient Services Retrofit NetworkGraph Url Repos

Slide 47

Slide 47 text

@HandstandSam #AndroidSummit Session Graph interface SessionGraph { val sessionManager: SessionManager val shoppingCart: ShoppingCart val userPreferences: UserPreferences }

Slide 48

Slide 48 text

@HandstandSam #AndroidSummit Multiple or Nested Graphs are AppGraph SessionGraph NetworkGraph ! Each module project needs their own graph ! Each graph is similar to a Dagger @Component

Slide 49

Slide 49 text

@HandstandSam #AndroidSummit ! Each Module can contain it’s own graph ! Doesn’t need a static instance unless there are Activities or Fragments Graphs in Modules

Slide 50

Slide 50 text

@HandstandSam #AndroidSummit ! Use the `by lazy` language feature of Kotlin to delay initialization, but cache result. Leveraging `by lazy` class AppGraph { val networkGraph by lazy NetworkGraph(config = config) }

Slide 51

Slide 51 text

@HandstandSam #AndroidSummit ! Create as needed ! Create Graph during Application::onCreate() if required by Activity/ Fragment for possible onProcessRestore bugs Setting up Your Graphs

Slide 52

Slide 52 text

@HandstandSam #AndroidSummit GRAPH BEING SETUP

Slide 53

Slide 53 text

@HandstandSam #AndroidSummit GRAPH BEING ACCESSED IN ACTIVITY

Slide 54

Slide 54 text

@HandstandSam #AndroidSummit RECAP: The DIY Recipe

Slide 55

Slide 55 text

@HandstandSam #AndroidSummit The DIY Recipe ! Kotlin ✅ ! Constructor Injection ✅ ! No Annotations or Code Generation ✅ ! Some Hacks for Activities & Fragments

Slide 56

Slide 56 text

@HandstandSam #AndroidSummit Challenges - Nothing is Perfect ! Static Availability for Activities and Fragments ! Onboarding ! Scoping

Slide 57

Slide 57 text

@HandstandSam #AndroidSummit Key Takeaways ! You don’t HAVE to use a Dependency Injection Library, Dagger ! There are no magic annotations. @Inject (JSR-330) ! Kotlin language features make this concise and straightforward ! Dependency Injection is critical for any app

Slide 58

Slide 58 text

@HandstandSam #AndroidSummit Thank you.