Interview Prep Zoneby CuriouserLabs

Question 5 of 5 · senior level

Explain dependency injection without a framework. What do coupling and cohesion actually measure?

🎤 Say this first

DI is just: classes declare dependencies as constructor parameters (as interfaces), and something outside wires them — a framework, or ten lines of new in main() (the composition root). It inverts control over construction, making dependencies explicit, swappable, and unit-testable with fakes. Cohesion measures how much a module's pieces belong together (one reason to change); coupling measures how much modules know about each other. Good design maximizes cohesion within, minimizes coupling between — DI reduces the worst coupling: to concrete implementations and construction details.

The full picture

DI is a pattern, not a framework
interface Notifier { void send(String to, String msg); }
final class EmailNotifier implements Notifier { … }

final class OrderService {
    private final OrderRepo repo;          // depends on ABSTRACTIONS
    private final Notifier notifier;
    OrderService(OrderRepo repo, Notifier notifier) {   // constructor injection
        this.repo = repo; this.notifier = notifier;
    }
}

// The composition root — the ONLY place that knows concretes:
public static void main(String[] a) {
    var service = new OrderService(new JdbcOrderRepo(ds), new EmailNotifier(smtp));
}
// Tests: new OrderService(new InMemoryRepo(), (to, msg) -> {})  — no framework, no mocks needed
  • Service locator vs DI: a locator hides dependencies (you must read the body to know them) and couples everything to the locator — DI keeps the signature honest.
  • What frameworks add on top of the pattern: lifecycle management, scopes, AOP interception, configuration binding, conditional wiring — value at scale, not magic.
  • Coupling has flavors — worst to best: content/common (shared mutable globals) → control → stamp → data. DI plus immutable message types pushes you toward data coupling.
  • A quick cohesion test: can you name the class without 'And' or 'Manager/Util'? Do its methods use most of its fields (LCOM intuition)?

🔄 Likely follow-up questions

  • What is a composition root and why should it be the only place that references concrete infra?
  • How does constructor injection interact with immutability and thread safety?
  • When does a service locator remain legitimate? (plugin systems, break-glass)