Say you have a class named AbcClass
.
If AbcClass
depends on AnotherClass
, and AnotherClass
eventually needs to make a network call (e.g. to S3, Databse, GIS, some other party), then don't instantiate AnotherClass
inside AbcClass
.
AnotherClass
should be injected into the constructor of AbcClass
.
Say AnotherClass
is instantiated inside AbcClass
.
When you write a test for AbcClass
, AnotherClass
will inevitably make a network call.
Network calls are unreliable and unpredictable. You have less control over it.
When you're unit testing AbcClass
, you want to test it in isolation and not have to depend on a network call.
You could mock AnotherClass
that is inside AbcClass
, but it's harder to mock it.
It's better to inject AnotherClassMock
into the constructor of AbcClass
so that u have complete control over the behavior of AbcClass
.
This makes AbcClass
less coupled to AnotherClass
.
Loose coupling + high cohesion is one of the hallmarks in software development. Loose coupling / high cohesion makes your program:
- easy to extend
- easy to maintain and debug
- easy to read and reason about
Pieces of code that belong together should stay together. For example, you take the train and hop in to carriage 1.
- You put your handbag in carriage 2.
- You put your luggage in carriage 3.
- You put your backpack in carriage 4.
It doesn't make sense. You, your handbag, your luggage and your backpack should stay with you on carriage 1.
https://en.wikipedia.org/wiki/Loose_coupling
https://en.wikipedia.org/wiki/Cohesion_(computer_science)
What's better than dependency injection? Dependency inversion of course. See https://khalilstemmler.com/articles/tutorials/dependency-injection-inversion-explained