kosi-libs / Kodein

Painless Kotlin Dependency Injection
https://kosi-libs.org/kodein
MIT License
3.19k stars 174 forks source link

Service locator anti pattern #92

Closed jlo-photobox closed 6 years ago

jlo-photobox commented 6 years ago

Hi! Was evaluating the available DI options in kotlin when I stumbled upon Kodein and couldn't help but notice that the example, and all the documentation I've stumbled upon, implements a service locator anti pattern.

http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/

Basically, suppose ServiceA depends on ServiceB and ServiceC. If I were to integrate Kodein as described in the Readme, I'd have to expose ServiceA (and any code with dependencies, meaning a large part of the codebase) to an external dependency I have no control over.

When testing ServiceA, I'd have to setup a Kodein instance, and mock ServiceB and ServiceC, this would also pollute my tests with an external dependency and add complexity (setting up Kodein) for no reason whatsoever.

In contrast, implementing dependency injection without falling into that anti-pattern would look like ServiceA depending in its constructor with ServiceB and ServiceC, and only outside of the class, as detached as possible from the rest, a dependency injection framework would be used to create the dependencies for me.

In the tests, I'd just have to mock ServiceA and ServiceB which are actual dependencies of the class, and Kodein would also be decoupled from them.

d3xter commented 6 years ago

What would you suggest?

jlo-photobox commented 6 years ago

I think that a good handling of this is done for instance in Autofac, where they highlight the dangers of taking a wrong approach with a DI tool, and adding a whole section in its documentation on how to isolate your codebase from it:

http://autofaccn.readthedocs.io/en/latest/faq/isolate-autofac.html?highlight=anti%20pattern#service-location

In the case of Kodein, I've only seen this section to serve a similar purpose:

https://salomonbrys.github.io/Kodein/#_transitive_dependencies

However in the next section it instructs to pass in the Kodein instance, and use it as a service locator, without cautioning the user about it:

https://salomonbrys.github.io/Kodein/#_being_responsible_for_its_own_retrieval

In general, feels like the documentation of Kodein is prodding towards coupling the codebase to an external dependency, which shouldn't really be encouraged.

SalomonBrys commented 6 years ago

Kodein is not a Service Locator: it is a Dependency Retrieval Container. There are differences that where explained thouroughly elsewhere.

Kodein does support properties retrieval (which makes the class dependent on Kodein) and constructor injection (which makes it independent).

I do agree that the current documentation has a heavy bias toward dependency retrieval. I've re-written the version 5.0 documentation with this in mind, trying to explain both approaches and their drawbacks.

Keep in mind that Kodein IS opinionated. It provides a container that allows retrieval in a very "Kotlin-esque" way. I believe there are many ways to do DI and to have module independance. Kodein is one.

Salomon.