Skip to content

Dependency Inversion — Loose Coupling

High-level policy must not depend on low-level detail. Both depend on abstractions, and the abstraction is owned by the high-level side.

Rules for agents

  • Domain/business logic must not import database drivers, HTTP clients, SDKs, or file APIs directly.
  • Pass dependencies in (constructor or function argument). Do not construct them inside, and do not reach for globals or singletons.
  • Define the interface in terms of what the caller needs (UserStore.find(id)), not what the vendor offers.
  • Keep concrete wiring in one composition root — main, a factory, or a DI container — at the edge of the app.
  • No clock, randomness, network, or filesystem access hidden inside pure logic; inject them so tests can control them.

Payoff

Swappable infrastructure, fast tests without mocks-of-mocks, vendor changes confined to one adapter.

Smells

import boto3 inside a domain module, new Database() in a constructor, tests that need a live service, a rename in one library rippling through business code.