Node.js Backend — What the Framework Hides
Dependency Injection — What It Means to Take It as an Argument
In one line
Dependency injection is not a difficult concept; it means receiving things as arguments. If you pass in from outside instead of referring to a global directly, you can pass in something else when testing.
Why it is needed: not for the sake of tests
If you learn DI as "something you use because of testing," the purpose is off. The real reason is marking in the code the places where things can be swapped.
Say you move the repository from PostgreSQL to the front of a Redis cache. If a handler calls
db.query(...) directly, you have to fix every handler. If the repository is received
as an argument, only the side that passes it in changes. Testability is a byproduct of that property.
Building it by hand
export function createApp({ store }) {
return async function handle(req) { /* store 를 쓴다 */ };
}
All a framework does is find this { store } automatically and pass it in.
Nest's providers and Spring's Beans are that automation. If you do not know
what the automation hides, you will not know where to look when injection fails.
In the field
When you are asked "why do you use DI?" in an interview, the answer is usually "because it makes testing easy." It is not a wrong answer, but it is half of one. The purpose is to invert the direction of dependencies so that a higher-level module is not tied to the implementation of a lower-level module, and testability is the result.
And the place where DI falls apart in practice is always the same: the moment someone imports one global singleton directly because it is "convenient." From then on, that module can no longer be swapped out.