skip to content

Low Coupling (GRASP)

An evaluative principle rather than a recipe: when two placements are otherwise equal, choose the one that creates fewer dependencies. Interviewers use it to see whether you weigh alternatives instead of picking the first placement that works.

part ofSoftware design & architectureoverview, primer and where to startread it →
on this pageshow

questions

5

In the GRASP set of object-oriented design principles, what does the Low Coupling principle say, and why does it matter?

level: juniorimportance: must knowfreq 78%

answer

  1. Evaluative, not constructive — a tie-breaker
  2. Fewer/weaker dependency edges wins
  3. Payoffs: change isolation, reuse, comprehension, testability
  4. Zero coupling = a program that does nothing
  5. Always paired against High Cohesion

basics

~20 s

Low 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 s

Coupling 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
pseudocode
// 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

for a junior

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.

for a middle

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.

for a senior

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.

for a principal

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.

context

open as a page

Applying the GRASP Information Expert principle (give a responsibility to the class holding the data it needs) sometimes produces a design with heavy dependencies. How do you use GRASP's Low Coupling principle to resolve that conflict, and what does Pure Fabrication contribute?

level: seniorimportance: must knowfreq 46%

basics

~20 s

Information Expert proposes a home for a responsibility; Low Coupling checks the bill. If the expert class would have to depend on infrastructure or many collaborators, move the responsibility to a made-up helper class — a Pure Fabrication — that keeps the domain class clean.

open as a page

Coupling is often described as having degrees of strength rather than being simply present or absent. Name the classic degrees of coupling from worst to best and explain what distinguishes them.

level: middleimportance: should knowfreq 52%

basics

~20 s

From worst to best: content (one element reaches into another's internals), common (shared global state), external (shared external format), control (one passes a flag telling the other what to do), stamp (passes a whole record when only a field is needed), and data (passes just the values needed).

open as a page

How would you measure coupling in a codebase, and when is deliberately accepting higher coupling the better engineering decision?

level: principalimportance: should knowfreq 30%

basics

~20 s

Count incoming dependencies (afferent) and outgoing ones (efferent) per module, plus dependency-cycle checks. Accept higher coupling when the alternative is layers of indirection nobody needs — for stable, rarely-changing dependencies, or in small, short-lived, or performance-critical code.

open as a page

Connascence is a model that classifies dependencies between software elements more finely than simply calling them 'coupling'. What are its three axes, and how does it make the goal of low coupling actionable?

level: seniorimportance: nice to knowfreq 16%

basics

~20 s

Connascence means two pieces of code must change together to stay correct. It grades each dependency by strength (how hard it is to spot and fix), degree (how many places are involved) and locality (how far apart they are). Reduce strength, degree, or distance.

open as a page