A dependency exists when one component relies on another to deliver behavior. Dependencies are necessary for collaboration, but they also create coupling: a change or bug in one component can affect clients without their code changing. The maintenance goal is not zero dependencies; it is deliberate, limited dependencies that do not let complexity or change propagation escape control. section 4.0 section 1.2.3
Prefer dependencies on stable abstractions rather than volatile implementation details. Information hiding lets a component evolve internally while clients rely only on the minimum information they need. Before exposing or consuming an API detail, ask whether clients will be affected by refactoring it, whether it changes frequently, and whether a more stable interface can hide it. section 4.2 section 1.2.3
Control dependency growth with practical design checks:
- Treat a class with many collaborators as a possible design problem; its interaction complexity and exposure to change both increase. section 4.3
- When adding functionality, weigh expanding an existing unit against adding a linked class: one increases local complexity, while the other increases coupling. section 4.3
- Break down units whose dependency sets have become too large, aiming to limit the scope of future changes. section 4.3
- Avoid depending on details a client does not need; conceal volatile implementation choices behind a stable abstraction where possible. section 4.2
Containing a payment-library dependency
A payment gateway library may require its own PaymentDetails type and API calls. Instead of letting that external type spread through the domain, define an application-owned payment data structure and route calls through a PaymentGateway adapter. If the library changes, update the adapter rather than every caller. The wrapper can feel redundant, but it creates a boundary around code whose release cycle and breaking changes are outside your control. section 6.3
Dependency management is a tradeoff, not a rule to maximize separation at any cost. Delegating work to other classes is often preferable to making one class do everything, yet every added collaborator introduces trust, interaction, and potential ripple effects. Favor small units in both responsibility and dependency count, while choosing the simpler design that keeps likely changes contained. section 4.0 section 4.3
Trace how direct and transitive dependencies can carry changes into a dependent class, including changes outside its immediate collaborators. section 1.2.3
Inspect the adapter boundary that keeps third-party payment-library types and calls from spreading into domain code. section 6.3


























