Suggest an editImprove this articleRefine the answer for “How to implement DI in a layered architecture?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**DI (Dependency Injection)** is a way to inject dependencies between layers so that **each layer does not create objects itself**, but instead **receives them "from the outside"**: through a constructor, parameters, or a dependency-injection container. In a layered architecture, DI is needed to **loosen the coupling between layers** and make the system flexible, testable, and manageable. **Key point:** dependencies always point downward - the upper layer knows about the lower one, but not the other way around.Shown above the full answer for quick recall.Answer (EN)Image**DI (Dependency Injection)** is a way to inject dependencies between layers so that **each layer does not create objects itself**, but instead **receives them "from the outside"**: through a constructor, parameters, or a dependency-injection container. In a layered architecture, DI is needed to **loosen the coupling between layers** and make the system flexible, testable, and manageable. --- ### 1. The problem without DI Without dependency injection, the code looks like this: ```python class UserService: def __init__(self): self.repository = UserRepository() # dependency is created inside ``` Now `UserService` is *tightly coupled* to the specific `UserRepository` implementation. If you want to swap the database or test the service, you will have to rewrite the code. --- ### 2. The DI principle in a layered architecture The idea is that **each layer does not create its dependency**, but **receives it "ready-made" from the upper level or a container**: ```python class UserService: def __init__(self, repository): self.repository = repository ``` Now you can pass any implementation: ```python repo = PostgresUserRepository() service = UserService(repo) ``` → `UserService` no longer depends on which database is used. → Tests can substitute a `FakeRepository`. --- ### 3. Where to inject dependencies per layer | Layer | What is injected | Where | |---|---|---| | **Presentation layer** | Business-logic services | Into controllers / views | | **Business-logic layer** | Repositories, providers | Into services / managers | | **Data layer** | Connections, drivers | Into repositories | | **Infrastructure layer** | Cache, loggers, API clients | Into services or event handlers | --- ### 4. What this looks like in practice **Example in Python (no frameworks):** ```python class UserRepository: def get_user(self, id): ... class UserService: def __init__(self, repository): self.repository = repository def get_user_info(self, id): user = self.repository.get_user(id) return {"name": user.name, "email": user.email} class UserController: def __init__(self, service): self.service = service def handle_request(self, id): return self.service.get_user_info(id) # Dependency injection at the top level: repository = UserRepository() service = UserService(repository) controller = UserController(service) ``` --- ### 5. DI containers (automation) Large projects use a **DI container**: a component that creates and passes dependencies to the right places by itself: - Python: `dependency-injector`, `injector` - Java: Spring Framework (`@Autowired`) - C#: .NET Core Dependency Injection - JavaScript/TS: NestJS, InversifyJS The container manages the whole dependency tree: ```python container = Container() container.wire(modules=[controllers, services, repositories]) ``` --- ### 6. The main rule > **Dependencies always point downward:** > the upper layer knows about the lower one, but not the other way around. > > DI lets you change the lower layer's implementation without touching the upper one. --- **Summary:** DI in a layered architecture is a mechanism that wires connections between layers **through interfaces rather than hard object creation**. It makes the code flexible, testable, and ready to scale without a "domino effect."For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.