dependency-injectionlisted
Install: claude install-skill andr-ca/agentharness
# Dependency Injection
**One rule:** depend on abstractions, receive them via constructor, never create them internally.
---
## The Pattern
```python
# BAD — hard to test, tightly coupled
class OrderService:
def __init__(self):
self.db = Database() # creates its own dependency
self.email = EmailClient() # can't inject fakes in tests
# GOOD — testable, decoupled
class OrderService:
def __init__(self, db: Database, email: EmailClient) -> None:
self.db = db
self.email = email
```
```typescript
// BAD
class OrderService {
private db = new Database(); // hidden dependency
}
// GOOD
class OrderService {
constructor(private db: Database, private email: EmailClient) {}
}
```
---
## Rules
| Do | Don't |
|---|---|
| Inject dependencies via constructor | Create dependencies with `new` inside a class |
| Depend on interfaces/protocols | Depend on concrete types when an abstraction exists |
| Make dependencies explicit | Use service locators (`Container.get(...)`) inside business logic |
| Keep constructors simple — no logic | Do work in `__init__`/constructors |
| Use fakes/stubs in tests | Patch global singletons in tests |
---
## When to Use a DI Container
Use a container (FastAPI's Depends, tsyringe, Wire for Go) when:
- The object graph has 3+ levels of nesting
- You need lifetime management (singleton vs. transient vs. scoped)
- You need request-scoped dependencies (e.g., database sessions per HTTP request)