What is Inversion of Control and Dependency Injection?
Inversion of Control (IoC) is a design principle where the control of object creation and dependency management is transferred from the object itself to an external entity (a framework or container). The name describes what is inverted: traditionally, a class is in control of constructing its own dependencies; with IoC, that control is inverted — the class declares what it needs, and something else provides it.
Dependency Injection (DI) is the most common technique for implementing IoC. Instead of a class instantiating its dependencies with `new`, those dependencies are "injected" (passed in) from outside — typically via constructor parameters, setter methods, or an interface.
**Without DI (tight coupling):** ```python class OrderService: def __init__(self): self.db = PostgresDatabase(host='prod-db') # hardcoded self.email = SendgridEmailClient(api_key='...') # hardcoded ```
**With DI (loose coupling):** ```python class OrderService: def __init__(self, db: Database, email: EmailClient): self.db = db self.email = email ```
Now `OrderService` depends on abstractions (`Database`, `EmailClient` interfaces), not concrete implementations. In tests, you inject mocks. In production, you inject the real implementations. The class doesn't know or care which.
**Types of injection:** - **Constructor injection** (preferred): dependencies passed in `__init__` / constructor. Makes dependencies explicit and the object always valid after construction. - **Setter injection**: dependencies set via methods after construction. Allows optional dependencies but leaves objects in a partially-initialized state. - **Interface injection**: the dependency provides an injector interface the class implements. Rare and more complex.
**DI containers** (Spring, Angular, .NET DI, Guice) automate the wiring. You register types with the container, and it resolves the full dependency graph automatically. This removes manual wiring boilerplate but adds framework coupling.
The core benefits: **testability** (inject mocks/stubs), **replaceability** (swap implementations without changing the dependent class), **separation of concerns** (construction logic moved to the composition root), and **adherence to the Dependency Inversion Principle** (depend on abstractions, not concretions — the D in SOLID).
Correctly explains IoC as inverting control of dependency creation, defines DI as the mechanism, and shows how constructor injection enables mock substitution for testing.
Distinguishes IoC (principle) from DI (technique), covers all three injection types with trade-offs, explains DI containers vs. manual wiring, and connects to the Dependency Inversion Principle in SOLID.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment