By Brian Plummer ● droidcon New York City 2019 ● 2019/09/27
[連結]
[VIMEO]
[YOUTUBE]
With Koin 2.0 it’s time for us to evaluate this age old debate. What exactly do we mean by service locator vs dependency injection? Does it matter in a modern age? I will discuss this topic along with how both libraries are implemented with an emphasis on their differences and how that affects us. By the end of this talk you will have an understanding of their implementations and the knowledge to assess which one is right for you!
[00:00] [Music]
[00:11] so let's get started first off why this
[00:15] talk and I want to be completely honest
[00:17] with you about why back in May
[00:20] coins you a coin to Oh came out and it
[00:23] was really looked really awesome I had a
[00:25] lot of great changes into it a lot of
[00:28] great performance improvements scoping a
[00:30] lot of stuff specifically for Android
[00:33] and honestly it looked really really
[00:36] neat and there was a ton of changes into
[00:38] it and that I mentioned performance
[00:40] improvements as well so naturally I
[00:44] wanted to check it out and it really
[00:47] kind of got me thinking this is new
[00:50] shiny library that's out that's gonna
[00:53] give me my dependencies for me but we
[00:55] have a lot of options today you know as
[00:58] I mentioned coin is dagger toothpick
[01:04] Cody in hope I said that right
[01:07] and some do-it-yourself dependency stuff
[01:11] with Kotlin that's kind of been on the
[01:13] forefront recently so we have a lot of
[01:15] options to pick from and so I'm gonna
[01:20] put the question to you all this is
[01:22] going to be really the only time I
[01:23] solicit the audience oh I'm one of these
[01:25] people I don't like to answer questions
[01:26] or participate but this will be the only
[01:28] time I'm going to ask that of you and
[01:29] I'm curious what we all use here and
[01:32] I'll go first
[01:33] I primarily a dagger user so I'd like to
[01:36] see a set of hands dagger users in the
[01:39] audience oh wow there's a good bit all
[01:41] right what about coin users do you have
[01:43] any current coin users okay a couple a
[01:46] couple how about toothpick I mentioned
[01:48] that oh you got one tooth pick user
[01:50] alright
[01:51] Cody in any code end users okay all
[01:55] right how about they do it yourself with
[01:58] Colin
[01:59] okay how about people in here that don't
[02:02] use anything don't use any library Wow
[02:06] so everyone here uses something okay wow
[02:09] that's really awesome it's really great
[02:11] to hear so let's take a couple steps
[02:13] back before we get too deep oh and let's
[02:16] talk about some of these terms and what
[02:18] they mean and so let's start with
[02:21] inversion of control what the heck is
[02:23] that well basically it just means
[02:25] swappable components we are inverting a
[02:29] typical flow of control and we're
[02:32] breaking things up some other synonyms
[02:34] that are used is decoupling and
[02:36] modularity you know a really good way to
[02:41] visualize this this concept is the the
[02:45] quintessential log or implementations we
[02:48] we have loggers like for example timber
[02:50] as one when we build our release apk the
[02:56] release implementation of the logger
[02:59] gets sucked up when we're doing a debug
[03:02] apk the debug version of it gets sucked
[03:04] up and we have these different
[03:06] implementations depending upon what
[03:08] we're using them for
[03:09] hence the swappable piece the inversion
[03:13] of control was coined in the late 90s by
[03:16] developer Michael Matson in one of his
[03:19] papers and I thought this was a really
[03:20] kind of an interesting quote here the
[03:22] inversion of control is sometimes named
[03:25] the Hollywood principle do not call us
[03:27] we call you another interesting player
[03:34] in this is Martin Fowler a developer who
[03:38] kind of popularized the term dependency
[03:40] injection in the early 2000s and if you
[03:42] start digging in some of these concepts
[03:44] you'll see his name pop up so as I
[03:48] mentioned he actually popularized the
[03:50] term dependency injection and he was one
[03:53] of the initial members of the signing
[03:55] members for the manifesto for agile
[03:57] software development so he was a big
[03:59] player in agile software before it was
[04:02] really a thing
[04:04] and you will even find out that there's
[04:06] a paper that he wrote from 2004
[04:09] suspiciously with the same name as this
[04:11] talk a little different though they call
[04:13] inversion of control containers and the
[04:16] dependency injection pattern so if I
[04:19] don't if I'm unable to give you what you
[04:21] want feel free to go home and google
[04:23] this and read the paper it's very it's
[04:26] worthwhile and I would recommend it
[04:27] another really interesting thing about
[04:29] Martin Fowler is he has written about a
[04:33] whole plethora of patterns and one of
[04:35] the more interesting ones that popped up
[04:36] was something called the strangler fig
[04:38] pattern which I thought was kind of
[04:39] interesting it's about supplanting
[04:41] systems and I just mention it just
[04:43] because it's odd and it has an odd
[04:44] sounding name and if you're interested I
[04:46] would recommend checking it out so on
[04:49] our journey dependency injection and if
[04:51] you actually google dependency injection
[04:54] this is the definition that will pop up
[04:56] it's a technique whereby one subjects
[04:59] applies the dependencies of another
[05:01] object it seems pretty straightforward
[05:03] there's no magic here
[05:04] we're just supplying the dependencies
[05:07] from one object to another object in
[05:11] dependency its dependency injection
[05:13] itself it implements this inversion of
[05:15] control through composition meaning it
[05:18] builds these objects through composition
[05:21] and not necessarily through inheritance
[05:22] but through composition and we'll see a
[05:24] little bit more about that well so let's
[05:29] I think I might have messed up here oh
[05:33] well so let's talk about a base case we
[05:37] talked about dependency injection let's
[05:39] look at something where we don't have
[05:41] any injection at all we're creating a
[05:43] repository object and our repository has
[05:46] a data source and you can see here we
[05:49] create when our repository object is
[05:52] created in the constructor we're
[05:53] initializing this data source from the
[05:55] factory we don't know where it's coming
[05:57] from
[05:58] or what it's exactly is it doing and
[06:00] it's kind of bad you know and why is
[06:03] this bad well there's no inversion of
[06:06] control as having there's no separation
[06:08] of concerns this repository is creating
[06:12] this data source internally and we don't
[06:15] even really have that
[06:16] to need to market if we want if we
[06:18] wanted to test our repository there's no
[06:20] way we could create a fake object to
[06:23] shove in it and to see what happens
[06:26] previous slides back we talked about
[06:28] inversion of control and the swap
[06:30] ability and this has no swap ability and
[06:34] no inversion of control so there's kind
[06:37] of three types of injection there's
[06:40] constructor and setter and interface and
[06:42] we'll kind of go over them individually
[06:45] so the first one contract constructor
[06:48] injection and it is as it sounds we are
[06:51] adding our dependency through the
[06:53] constructor you can see here we're
[06:54] creating our repository class and it is
[06:57] consuming the data source via the
[06:59] constructor one of the things I really
[07:03] like about constructor injection is it
[07:06] can show us bad smell if we have an
[07:08] object that has a lot of dependencies
[07:10] it'll be very very obvious to us here
[07:13] and we can start to think okay maybe I
[07:16] should refactor this so there's some
[07:17] value to that another type of injection
[07:21] the setter injection where we have a
[07:24] repository in the field that we're
[07:26] interested in consuming the data source
[07:28] it is a field on our object and the
[07:31] injector injects our data source onto
[07:35] our internal field
[07:37] hence setter injection and lastly
[07:42] interface injection and I'm including
[07:44] this at the just to be a little pedantic
[07:46] not really this isn't really used much
[07:50] today but the way this kind of works is
[07:53] the interface that we're talking about
[07:55] is basically the contract the thing
[07:57] between the object that's consuming the
[07:59] dependency and the injector so you can
[08:02] see at the very top that we have we
[08:04] define our interfaces as a inject
[08:07] datasource and it takes the data source
[08:09] that we want and our repository object
[08:12] it implements the interface and so it
[08:15] internally knows how to deal with given
[08:18] that data source so as the name kind of
[08:24] implies dagger
[08:25] it's a dependency injection framework
[08:26] how does it work it leverages a lot of
[08:30] this through compile-time verification
[08:32] of our dependencies and it does it it
[08:37] does it by generating I let me back up
[08:40] it's a compile-time verification and it
[08:43] also spits out generated code as well to
[08:46] do the glue and to accomplish the
[08:48] injection so for example here we have
[08:52] our main activity at the very top and we
[08:55] have our filled repository which is a
[08:57] late in it var and in the oncreate of
[09:00] our activity we're basically saying
[09:02] application component inject this and at
[09:06] compile time dagger goes through all the
[09:09] legwork of creating these factories to
[09:11] actually create the glue that does it
[09:14] for us OOP so you can see right there
[09:17] that's our late init var our field that
[09:20] we want to be injected here we do the
[09:23] inject and then that's the actual
[09:25] generated code that sets our member so
[09:33] let's go let's start with service
[09:35] locators
[09:44] if you were to look up service locators
[09:47] on Google this is kind of the first
[09:49] definition that really pops out at you
[09:50] it's a pattern which is used to
[09:52] encapsulate the processes involved in
[09:55] obtaining a service with a strong
[09:57] abstraction layer it's a pattern it's
[09:60] used to encapsulate the processes
[10:01] involved in obtaining a service with a
[10:03] strong abstraction layer that sounds
[10:05] very similar to dependency injection so
[10:09] if we were to look here's an example of
[10:10] kind of a static service locator we can
[10:13] see here our service locator is declared
[10:15] as an object it's static it's providing
[10:18] a data source the data source is the the
[10:20] interface and the concrete is the data
[10:23] source Emma what's actually being
[10:25] invoked and then below that we say
[10:28] service locator data source pretty
[10:30] straightforward more of a dynamic
[10:34] example if we were to kind of have our
[10:36] own homebrew version of a service
[10:38] locator something very simple with a
[10:41] Maps key value pairs to keeping the
[10:44] string the value being the actual
[10:46] service that were interested in and in
[10:49] here you can see we say service locator
[10:52] get we pass it the key and then we
[10:55] dynamically get the value back coin
[11:01] works by doing this run time compared to
[11:06] daggers compile time code generation an
[11:10] example of that is when we get our
[11:13] repository using this lazily inject by
[11:15] keyword here it actually calls into a a
[11:18] helper method and you can actually kind
[11:20] of see as reify types and gets what we
[11:24] want and that's kind of how it resolves
[11:26] our dependency at runtime so that's all
[11:32] fine and dandy what are some of the
[11:34] conclusions both provides separation of
[11:36] concerns both of these frameworks
[11:39] abstract how we create our dependencies
[11:42] and the real differences is how they're
[11:46] provided
[11:49] and lastly they're not really mutually
[11:52] exclusive and what do I mean by that we
[11:56] could actually use both of these
[11:58] patterns together if we were so inclined
[12:01] you know an example of that is the
[12:03] dependencies are actually created with
[12:05] injection but the actual values can be
[12:08] served up with a service locator we can
[12:14] create the dependencies with a
[12:15] constructor injection regardless if
[12:18] we're using coin or some other service
[12:19] based locator pattern we can force this
[12:22] upon ourselves if we choose so what are
[12:29] some thoughts guarantees when we're
[12:33] considering these frameworks what
[12:37] guarantees do we have and when I what I
[12:41] mean by that is the dependency injection
[12:45] slant the compile time we're guaranteed
[12:49] at compile time and the verification is
[12:51] done for us at compile time whereas the
[12:53] service locator it's more of a runtime
[12:56] guarantee and what's important to us
[13:01] hard guarantees or pinky swears as I
[13:04] like to call not to diminish one or the
[13:07] other
[13:07] but maybe it's something that we should
[13:09] consider and something we should talk
[13:11] about what's important to us as we're
[13:13] considering these libraries also the
[13:17] costs involved what are the cost as I
[13:19] mentioned compile time versus run time
[13:22] and there are costs involved there are
[13:24] no free lunch and what does that mean
[13:28] for us when we choose these also the
[13:31] complexity do we want something that's
[13:34] maybe right out of the gate is easy to
[13:36] understand or something that has a
[13:37] little bit of a higher learning curve
[13:40] and something I would require a little
[13:41] bit more of a handoff to other
[13:43] developers that maybe take our place and
[13:47] again more costs build time
[13:50] what's the build time what's the impact
[13:52] these are all sort of thoughts and
[13:54] questions we should ask ourselves when
[13:56] you choose one of the
[13:58] libraries and as I kind of implied we
[14:03] should really think about that ourselves
[14:04] and what our principles are kind of what
[14:08] our situations are to sometimes you know
[14:10] are we the only developer are we on a
[14:12] team with other people that already have
[14:14] solutions and opinions its greenfield
[14:19] versus existing does it make sense to
[14:21] rip out something that is already
[14:23] working and replace it with something
[14:24] else if we're Greenfield can we use
[14:28] something new and exciting what are our
[14:31] limitations and as I kind of hinted to
[14:34] earlier onboarding of new developers
[14:37] then the complexity how much effort how
[14:39] much time will be spent doing this and
[14:48] lastly what do we expect from these
[14:50] libraries what do we want we're not
[14:54] there's a reason why we're using them
[14:56] and it's important to us primarily these
[15:00] libraries abstract how we construct our
[15:03] dependencies and that is the real proof
[15:05] in the pudding and that's what we really
[15:08] want and expect and that leads to
[15:12] improved tests yeah improve testability
[15:14] as well if we're forced to construct our
[15:18] dependencies in a certain way primarily
[15:21] through constructor injection then that
[15:23] forces us to think about what is
[15:27] required for these objects and it will
[15:29] lead to improved testability and scoping
[15:33] lastly scoping we have this expectation
[15:35] of having a scope around lifecycle of
[15:39] these objects whether it's a singleton
[15:40] or whether that's wired into something
[15:44] more Android specifically we expect to
[15:47] be able to have scoping for these
[15:50] objects that are given to us and lastly
[15:54] I kind of want to consider I want us to
[15:58] consider this Martin Fowler mentioned
[16:01] the choice between the service locator
[16:03] and dependency injection is less
[16:05] important the principle of separating
[16:07] configurations from the use of services
[16:09] within
[16:09] location and so this kind of implies
[16:12] that us using something is better than
[16:15] nothing and I would agree to that and if
[16:22] there's anything take away from this
[16:24] talk it would probably be that and
[16:26] that's it it's very short talk thank you
[16:29] so much
[16:31] [Applause]