DEV Community

Cover image for How I Started Seeing Dependency Injection a Bit Differently 😊🍺
Vỹ Khôi Đặng
Vỹ Khôi Đặng

Posted on

How I Started Seeing Dependency Injection a Bit Differently 😊🍺


Dependency Injection (DI): It’s Not Just About Clean Code—It’s About Saving Server Costs

Many developers view Dependency Injection (DI) as a high-level architectural concept for making code look “pretty.” But from my perspective, the ultimate goal of any advanced technique is simple: Enable the server to handle heavier loads while keeping the overhead costs low. DI is a secret weapon for exactly that.

1. The Anatomy of a Request: “The Object Cluster”
To understand DI, we first need to look at how a system (like .NET) processes a request. Every request enters the app as an object—eventually becoming part of the HttpContext.

To process this context, our application creates a “cluster of objects” linked together in a chain:

  • It starts with the Controller.
  • It dives deeper into various Services.
  • It reaches the Repositories, Logging, and Database Contexts. This is the core of OOP: everything is transformed into an object to be processed. Once the task is done, the cluster is disposed of.

2. The RAM Nightmare and the Birth of DI
The problem? If 1,000 or 10,000 requests hit your app simultaneously, creating this “object cluster” over and over again is incredibly expensive for your RAM and CPU. Without management, your server will choke.

This is why DI was born. While popularized by industry giants like Martin Fowler and Robert C. Martin (Uncle Bob), in the .NET world, it has become the “heart” that regulates the Lifetime of these objects.

3. The “Life & Death” Coordinator: Singleton, Scoped, and Transient
DI allows us to control how objects within that processing cluster live and die, ensuring we don’t waste a single byte of RAM. We do this through three main Lifetimes:

  • Transient (The Short-Lived): Created every time they are requested. Think of them like a paper napkin—use once and throw away. Best for lightweight, stateless logic.
  • Scoped (The Request-Lived): One object is shared across the entire cluster for a single HttpContext. Once the request is finished, its “role” ends. This is a massive RAM saver because we don’t recreate the same service multiple times within one thread.
  • Singleton (The Long-Lived): Created once when the app starts and lives until it shuts down. This is the “Big Boss” shared by millions of requests. It’s the ultimate resource saver, though it requires careful handling of data concurrency.

4. The Other Side of the Coin: Decoupling
Beyond RAM management, DI saves our sanity by ensuring our code isn’t “stuck together” through Dependency Inversion. It allows us to swap modules easily without breaking the whole chain. But that’s a deep topic for my next post!

Thanks for reading my take on DI. This is my first time writing about this, so if you have a different perspective or see any gaps, I’d love to hear your thoughts in the comments! Let’s share and learn together. 🍻

Top comments (0)