In the GRASP set of object-oriented design principles, what does the Low Coupling principle say, and why does it matter?
answer
- Evaluative, not constructive — a tie-breaker
- Fewer/weaker dependency edges wins
- Payoffs: change isolation, reuse, comprehension, testability
- Zero coupling = a program that does nothing
- Always paired against High Cohesion
basics
~20 sLow Coupling (GRASP) says: assign responsibilities so each class depends on as few other classes as possible. Fewer dependencies mean a change in one place breaks fewer others, and classes are easier to reuse, understand and test alone.
solid answer
~50 sCoupling measures how strongly one element depends on, knows about, or relies on others. GRASP (General Responsibility Assignment Software Patterns) frames Low Coupling as an evaluative principle: when you decide which class should get a responsibility, prefer the assignment that creates fewer or weaker dependencies. The payoffs are change isolation (a modification ripples less far), comprehensibility (you can read a class without loading its whole neighbourhood into your head), reuse (a class dragging ten collaborators along cannot be lifted into another context), and testability (fewer collaborators to stub). Coupling is unavoidable and not intrinsically bad — objects must collaborate — so the goal is not zero coupling but avoiding *unnecessary* or *strong* coupling, especially to volatile or concrete elements. Low Coupling is rarely applied alone: it is weighed against High Cohesion and the other GRASP patterns as a tie-breaker among otherwise acceptable designs.
code
pseudocode · 15 lines// High coupling: Register knows Payment's construction AND Sale's internals
class Register {
fun takePayment(sale, amount) {
payment = new Payment(amount, Clock.now(), currentCashier)
sale.payments.add(payment) // reaches into Sale's data
}
}
// Lower coupling: Register knows only Sale; Payment stays Sale's business
class Register {
fun takePayment(sale, amount) { sale.pay(amount) }
}
class Sale {
fun pay(amount) { payments.add(new Payment(amount)) }
}go deeper
Define coupling as "how much one class depends on another", state the rule (prefer the design with fewer dependencies), and name two benefits: easier change and easier testing.
Add that it is evaluative and used as a tie-breaker between Information Expert / Creator candidates, that coupling has strength as well as count, and give a concrete before/after example.
Frame it against High Cohesion as a joint optimisation, discuss volatility-weighted coupling (depend on stable abstractions), and connect it to Protected Variations, Indirection, and the Dependency Inversion Principle.
Discuss coupling at the architectural scale — module and service boundaries, afferent/efferent dependency metrics, the cost of indirection introduced to lower coupling, and when accepting coupling is the right economic call.
## The vocabulary first **Coupling** is the degree to which one software element (class, module, service, function) depends on another. If element A must be changed whenever element B changes, A is coupled to B. Typical sources of coupling in object-oriented design: - A holds a **reference/field** of type B. - A **calls a method** on B, or **creates** an instance of B (`new B(...)`). - A **inherits** from B (inheritance is the strongest common form: the subclass sees protected internals and is bound to B's structure). - A **reads or writes B's data** directly. - A depends on a **type in B's signature** (parameter, return type, thrown error). **GRASP** stands for *General Responsibility Assignment Software Patterns* (Craig Larman). It is a catalogue of nine naming-and-reasoning aids — Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, Protected Variations — that help answer the single hardest OO question: **which class should be responsible for what?** ## What Low Coupling actually states > *Assign responsibilities so that coupling remains low. Use this principle to evaluate alternatives.* Note the second sentence. Low Coupling is an **evaluative** principle, not a constructive recipe. It does not tell you what to build; it tells you how to *compare* two candidate designs. It is most often used as a **tie-breaker**: Information Expert or Creator may suggest two plausible homes for a responsibility, and Low Coupling picks the one that adds fewer dependency edges. ## Why it matters — the four concrete payoffs 1. **Change isolation (the big one).** Cost of software is dominated by change. If `Order` knows about `SmtpMailer`, `PdfRenderer`, `TaxTable`, and `LoyaltyEngine`, then any of those four changing can force `Order` to be re-read, re-compiled, re-tested, re-deployed. High coupling turns local edits into cascades — the *ripple effect*. 2. **Comprehensibility.** To understand a highly coupled class you must first understand everything it touches. Low coupling means the unit of understanding is small. 3. **Reuse.** A class can only be reused where all its dependencies also exist. A `PricingCalculator` that only depends on plain value types can move into a batch job, a test, or another product; one that depends on a live database session cannot. 4. **Testability.** Every collaborator is something a unit test must construct, stub, or mock. Tests full of mocks are usually a coupling smell, not a testing-style choice. ## Coupling is not evil — it is a budget A system of totally uncoupled objects does nothing; collaboration *is* the program. Two consequences follow: - **Zero coupling is not the goal.** The goal is to avoid *unnecessary* coupling and to *weaken* the coupling you must keep (depend on an interface rather than a concrete class; pass a value rather than a whole aggregate; call one method rather than reach through three). - **Coupling to stable things is cheap.** Depending on the language's standard collections, or on a pure value type, barely counts — those elements change rarely. Depending on a volatile, frequently-edited, third-party or unstable element is expensive. So the practical rule is: *minimise coupling to things that change*, and *prefer to depend on abstractions and stable elements*. ## A worked example A payment must be recorded against a sale. Two candidate assignments: - **(a)** `Register` creates the `Payment` and passes it to `Sale`: `Register` now knows both `Payment` and `Sale`. - **(b)** `Sale` creates its own `Payment` from an amount: `Register` only knows `Sale`. Both satisfy Creator reasonably. Low Coupling breaks the tie for **(b)** — the total number of dependency edges is smaller, and `Register` is insulated from `Payment` changing. ## How to spot high coupling in review - Long import/`using` lists at the top of a file. - **Train wrecks / Law-of-Demeter violations**: `order.getCustomer().getAddress().getCountry().getTaxRate()` — this couples the caller to four types at once. - Constructors with many collaborators, or tests that need many mocks. - A change request that reliably touches the same five unrelated files. - Direct field access or downcasting into another class's internals. ## The tension you must be able to name Low Coupling pulls against **High Cohesion** (the other evaluative GRASP principle: keep each class's responsibilities focused and related). You can always drive coupling to near-zero by dumping everything into one god class — coupling collapses, cohesion collapses with it, and the design gets worse. The two must be optimised **together**; either one alone is a degenerate objective.
- Is coupling to a class in the standard library as bad as coupling to a class your team wrote last week?No. The cost of coupling scales with the volatility of what you depend on. Standard-library and stable value types change rarely, so depending on them is cheap; depending on an unstable, actively-changing, or third-party element is what actually generates rework.
- If Low Coupling is always good, why not merge everything into one class so there are no inter-class dependencies at all?Because coupling then reappears *inside* the class as tangled internal state, and cohesion is destroyed. Low Coupling is only meaningful when optimised jointly with High Cohesion; alone it has a degenerate optimum (the god class).
Think of coupling as wiring in a house. Every appliance needs some wiring — that's collaboration. But if the doorbell is hard-wired through the oven, the fridge, and the boiler, replacing the doorbell means an electrician opening four walls. Low Coupling is running short, standard, labelled circuits so one thing can be swapped without a rewire.
saying these in an interview costs you the question
- Saying "coupling is always bad, aim for zero" — objects must collaborate; the target is unnecessary and strong coupling.
- Confusing coupling with cohesion (coupling is *between* elements, cohesion is *within* one).
- Treating Low Coupling as a construction rule that dictates a class structure, rather than as an evaluation/tie-break criterion.
- Counting only the *number* of dependencies and ignoring their *strength* and *volatility*.
- Claiming inheritance reduces coupling — subclassing is one of the strongest coupling forms available.