← ClaudeAtlas

dependency-injectionlisted

Use when writing or reviewing code with object graphs, service dependencies, or testability concerns. Covers constructor injection, DI containers, lifetimes, and anti-patterns (service locator, ambient context, over-injection).
andr-ca/agentharness · ★ 1 · Code & Development · score 70
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)