The term is unfamiliar to me -- is it related to "fault injection"?
The term is unfamiliar to me -- is it related to "fault injection"?
But this makes testing A in isolation difficult. When testing A, you want to mock out B with an instance the test can manipulate.
So we want A to not create B, instead we want B to be "injected" into A. The general strategy of having B passed into A is called dependcy injection.
If you've ever written a constructor for a class that has arguments (within the constructor signature) that are used by the instance of the class when instantiated then you have done dependency injection, or put more simply 'passing stuff in' which was eloquently stated in another comment on this thread.
In any case, DI is not at all a new trendy term. Inversion of Control dates back to the gang of 4 patterns book from the '90s. Yes, constructor parameters are one way to implement DI, but not the only one. I'm ambivalent on the whole pattern movement, but they are a great educational tool for novice programmers, and it is good to have some standard terminology for core patterns.
To put it another way, constructor based DI is not simply the use of constructor parameters, it is understanding the OO design principle that side-effecting code should be isolated into objects, rather than just dumping a bunch of DB queries into your functions, like we did back in the stone age.
it makes the code cleaner and testable.
A. Also depended upon by other, coequal unrelated classes, possibly maintained by others, OR
B. Depended upon only by a single class (of higher functionality)
Situation A is sometimes called a portability interface; B might be called an internal structuring interface.
The difference has crucial implications for social power relationships between the human developers and users involved.
This way, your code isn't bound to a specific implementation.
Some DI frameworks even go so far and define all resources in a config file. This way you can switch out the implementation without a recompilation.
https://hasura.io/blog/build-fullstack-apps-nestjs-hasura-gr...
Dependency Injection solves the problem of when you want to create something, but THAT something also needs OTHER somethings, and so on.
In this example, think about a car.
A car might have many separate parts it needs:
class Car {
constructor(wheels: Wheels) {}
}
class Wheels {
constructor(tires: Tires) {}
}
class Tires {
constructor(rims: Rims, treads: Treads)
}
class Rims {
constructor() {}
}
class Treads {
constructor() {}
}
We can manually construct a car, like: const car = new Car(new Wheels(new Tires(new Rims(), new Treads())))
But this is tedious and fragile, and it makes it hard to be modular.With dependency injection, it allows you to register a sort of "automatic" system for constructing an instance of "new Foo()", that continues down the chain and fetches each piece.
class NeedsACar {
constructor(@Inject private car: Car) {}
}
And then "class Car" would have an "@Inject" in it's "constructor", and so on down the chain.When you write tests, you can swap out which instance of the "@Injected" class is provided (the "Dependency") much easier.
The alternative to dependency injection is for functions to instantiate dependencies internally rather than having them be passed in from the calling context.