Loose Coupling
- In Turkish
- Gevşek Bağlılık
In short
Loose coupling is a design principle in which components depend on each other as little as possible, so one can change without breaking the others.
What is loose coupling?
Coupling describes how much one part of a system depends on the details of another. In a tightly coupled design, a class, module, or service knows a lot about another's internals, such as its concrete class, database tables, or data format, so changing one forces changes in the other. Loose coupling reduces those dependencies to a small, stable contract, so each part can be changed, tested, replaced, or deployed more independently.
Common techniques include depending on interfaces instead of concrete classes, passing dependencies in through dependency injection, communicating through well-defined APIs, and using events or message queues so the sender doesn't need to know who reacts. Encapsulation also helps, because other code can only rely on what is deliberately exposed. At the system level, microservices that share a database are tightly coupled even if they are deployed separately, while services that own their data and talk through versioned APIs are loosely coupled.
A good analogy is a wall socket and a lamp: any lamp with a standard plug works in any socket, and you can replace either one without rewiring the house. A lamp wired directly into the wall would be tightly coupled. Loose coupling shows up everywhere, from small functions and classes to plugin systems, microservices, and event-driven architectures.
Loose coupling is often discussed together with high cohesion, but they are different ideas. Cohesion is about how closely the things inside one module belong together, while coupling is about how much separate modules depend on each other; good designs aim for high cohesion and loose coupling. Loose coupling is also not the same as no coupling, since parts must still communicate, and adding too many layers of indirection can make code harder to follow.
Key takeaways
- Coupling measures how much one component depends on another's details.
- Loosely coupled parts can be changed, tested, and deployed more independently.
- Interfaces, dependency injection, APIs, and events reduce coupling.
- Aim for high cohesion within modules and loose coupling between them.
- Too much indirection has costs, so decouple where change is likely.
Example
// Tightly coupled: the service creates a specific email client itself
// class SignupService { private mailer = new SmtpMailer("smtp.example.com"); }
// Loosely coupled: the service depends only on a small interface
interface Notifier {
send(to: string, message: string): Promise<void>;
}
class SignupService {
constructor(private notifier: Notifier) {}
async register(email: string) {
// ...save the user...
await this.notifier.send(email, "Welcome aboard!");
}
}Readers ask
What is the difference between loose coupling and tight coupling?
In tight coupling, components depend on each other's internal details, so a change in one often breaks the other. In loose coupling, they interact through small, stable contracts such as interfaces or APIs, so each can change independently.
What is the difference between coupling and cohesion?
Coupling is about dependencies between modules, while cohesion is about how well the responsibilities inside a single module fit together. Well-designed code has loose coupling between modules and high cohesion within each one.
How do microservices achieve loose coupling?
Each service owns its own data, exposes a versioned API or publishes events, and avoids sharing databases or internal code with other services. This lets teams deploy and scale services independently.
See also
- Dependency InjectionSoftware Architecture, p. 12Dependency injection is a design technique in which an object receives the other objects it needs from the outside instead of creating them itself.
- InterfaceProgramming Fundamentals, p. 29An interface is a named set of method and property signatures that a type promises to provide, without saying how those members are implemented.
- Separation of ConcernsSoftware Architecture, p. 37Separation of concerns is a design principle that divides a program into distinct parts, each responsible for one clearly defined aspect of its behavior.
- MicroservicesSoftware Architecture, p. 27Microservices are an architectural style where an application is split into small, independently deployable services that communicate over a network.
- Event-Driven ArchitectureSoftware Architecture, p. 18Event-driven architecture is a software design style in which services communicate by producing and reacting to events, such as an order being placed.
- Hexagonal ArchitectureSoftware Architecture, p. 21Hexagonal architecture is a way of structuring software so the core business logic talks to the outside world only through ports and swappable adapters.
- CohesionSoftware Architecture, p. 7Cohesion is a measure of how closely the responsibilities inside a module, class, or service belong together, and high cohesion is a sign of good design.
Spotted a mistake or something missing on this page?Suggest an edit