I have been reading alot about dependency injection thinking that it may be some really advanced way to program, but I can't see the difference between just avoiding global state, as when there is no global state then you are forced to pass in all dependencies to objects.
Can someone please explain to me as I think I may be missing the point about what dependency injection is?
Using global variables causes very tight coupling of code. Using global variables causes namespace pollution. This may lead to unnecessarily reassigning a global value. Testing in programs using global variables can be a huge pain as it is difficult to decouple them when testing.
Dependency injection creates clients that demand configuration details to be supplied by construction code. This can be difficult when obvious defaults are available. Dependency injection can make code difficult to trace (read) because it separates behaviour from construction.
Dependency injection moves the dependencies to the interface of components. This makes it easier to see what dependencies a component has, making the code more readable. You don't have to look through all the code to see what dependencies you need to satisfy for a given component. They are all visible in the interface.
The goal of the dependency injection technique is to remove this dependency by separating the usage from the creation of the object. This reduces the amount of required boilerplate code and improves flexibility.
Dependency injection is about decoupling code.
When you avoid the use of globals by passing arguments you are decoupling code. You are removing the dependency the code has on the globals.
You can generalize this decoupling to more than just the avoidance of globals. Take the following code:
def foo(arg):
return ClassBar(arg).attr
foo(1)
The function foo
is dependent on or tightly coupled to ClassBar
. The reason this is not good is you will be forced to update foo
when:
ClassBar
changeClassBar
to something elseattr
from a different objectIf the code was rewritten:
def foo(instanceBar):
return instanceBar.attr
foo(ClassBar(1))
You've pushed the coupling up to the caller. This removed the dependency from the definition of foo
. This frees you from having to update foo
in the cases outlined above. The more of your code that is decoupled, the fewer code changes you'll need to make.
What I understand about dependency injection is that you leave out the details of creating an object and only declare that such an object is needed. A framework for example will set this object later on before it's needed.
So the value here is the separation of concerns. This is useful for testing when you will inject a mockup of the real object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With