Coupling is the degree to which a component depends on another. Some dependency is necessary: services collaborate with repositories and entities rather than doing everything alone. The risk begins when a class or module knows too much about dependencies, relies on many of them, or depends on details likely to change. A change can then ripple through clients, increasing maintenance work and making defects spread beyond the code that was edited. section 1.2.3 section 4.0
Aim for dependencies on stable abstractions and clear contracts, not on implementation details. A stable abstraction is less likely to force client changes. At module boundaries, expose simple APIs, hide internals, and preserve backward-compatible communication where possible. This lets a component evolve its implementation—such as its caching strategy—without requiring its consumers to change. section 5.1.6 section 7.3 section 7.5
Contain infrastructure dependencies
Keep file access, third-party library calls, persistence code, and file-generation details behind a focused boundary. A Configuration class can read a file and return a clean value to domain code; a repository or data access object can contain Hibernate access; an adapter can contain Excel generation. For a frequently changing payment library, add a wrapper so the rest of the system has no direct dependency on it. This localizes future changes and makes replacements during testing easier. section 6.1 section 6.3.1
Treat coupling as a design constraint rather than an absolute ban:
- Avoid coupling to internal classes or leaked implementation details; document the supported API and enforce boundaries with tools such as ArchUnit or JPMS. section 7.3.2
- Monitor dependency trees as systems grow. Extract narrowly needed functionality or offer a less coupled interface, but do not respond by creating countless tiny modules. section 7.3.3
- Accept framework dependencies where they are appropriate. Use Spring capabilities in controllers, for example, while keeping domain objects free of Spring code; isolate less stable external integrations more aggressively. section 6.3.1
- When unavoidable business coupling remains, design compatible communication where possible and document it, including alerts for breaking changes. section 7.1.4
Trace how a direct dependency and its transitive dependencies can expose a class to cascading change. section 1.2.3
















