skip to content

Law of Demeter

Talk only to your immediate collaborators instead of reaching through them with call chains like a.getB().getC().doThing(). You will learn how those train wrecks bake structural knowledge into callers, and what the wrapper methods that fix it cost.

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

questions

6

What is the Law of Demeter (also called the "principle of least knowledge") in object-oriented design, and what is a "train wreck" call chain?

level: juniorimportance: must knowfreq 58%

answer

  1. Only talk to immediate friends
  2. Don't talk to strangers
  3. a.getB().getC().do() = train wreck
  4. Mocks returning mocks = smell
  5. Tell, don't ask beats Hide Delegate

basics

~10 s

A design guideline: an object should only call methods on its immediate collaborators, not reach through them into strangers. A "train wreck" is a chain like order.getCustomer().getAddress().getCity().getName() that navigates someone else's object graph.

solid answer

~50 s

The Law of Demeter (LoD), or principle of least knowledge, says a method should only send messages to objects it directly knows: itself, its own fields, its parameters, objects it creates, and (in the original phrasing) globals in scope. It must not call a method on an object it got back from one of those calls — a "stranger". A train wreck is the visible symptom: order.getCustomer().getAddress().getCity().getName(). The calling code now depends on four types and on the exact shape of the graph connecting them. Any change — Address gains a nullable City, Customer stops owning Address directly — breaks callers that never should have known about it. LoD trades this structural coupling for delegation: the caller asks order.getCustomerCity() (or better, tells the order to do the work) and the knowledge of the graph stays where it belongs.

code

pseudocode · 8 lines
pseudocode
// Train wreck: caller knows Order -> Customer -> Address -> City
name = order.getCustomer().getAddress().getCity().getName()

// Delegation: each hop hidden behind one method
name = order.customerCityName()

// Better still - tell, don't ask: caller wanted an outcome, not data
order.printShippingLabel(printer)

go deeper

for a junior

Name it (principle of least knowledge), give the train-wreck example, say the fix is to ask your direct collaborator for what you need.

for a middle

Add the concrete costs — ripple change, mock-of-mock tests, null handling leaking to callers — and mention Hide Delegate as the mechanical refactoring.

for a senior

Frame it as controlling structural coupling to the object graph, escalate from delegation to Tell-Don't-Ask, and note the middle-man cost of applying it dogmatically.

for a principal

Position it as one point on a coupling spectrum: it is a heuristic, doesn't apply to data structures, and its real value is that it keeps knowledge of graph shape from spreading across a codebase or across service boundaries.

## The core idea The Law of Demeter came out of the Demeter research project at Northeastern University (Karl Lieberherr, Ian Holland, ~1987). Despite the name, it is a **heuristic**, not a law — a style rule you apply with judgement. Its informal statements: - **"Only talk to your immediate friends."** - **"Don't talk to strangers."** - **"Principle of least knowledge"** — a unit should know as little as possible about the structure of anything other than itself. ### Terms, defined - **Object**: a bundle of data plus the operations on it. - **Method / message send**: calling an operation on an object (`a.doThing()` sends the message `doThing` to `a`). - **Collaborator**: another object that this object holds or receives, and uses to get its job done. - **Stranger**: an object you obtained *indirectly* — it was handed back to you by a collaborator. You didn't create it, don't hold it, weren't given it. - **Coupling**: how much one piece of code must know about another to work. **Structural coupling** here means knowing the *shape of the object graph* — who holds whom. ### The train wreck ``` city = order.getCustomer().getAddress().getCity().getName() ``` It's called a train wreck because the chained calls look like coupled railway cars. This one line encodes a claim: *an Order has a Customer, which has an Address, which has a City, which has a name.* Four types, three edges of the graph. The compiler will not warn you when that claim stops being true; you just get a cascade of edits, or a null dereference at runtime because one link in the chain became optional. ### Why it hurts 1. **Ripple effect on change.** Replace `Address` with a `PostalLocation`? Every caller that walked through it changes, even though those callers only ever wanted a city name. 2. **Testing pain.** To unit-test the caller you must build (or mock) the entire chain — a mock returning a mock returning a mock. "Mocks returning mocks" is a well-known LoD alarm bell. 3. **Null / absence handling leaks.** Each hop is a place something can be missing, and the *caller* — who has no business knowing — has to handle it. 4. **Encapsulation is defeated.** `Customer` declared a private field and then handed it out through a getter. Privacy of the *field* was preserved; privacy of the *design* was not. 5. **Logic migrates outward.** Behaviour that belongs inside `Order` or `Customer` accumulates in callers instead — the Feature Envy smell. ### Fixing it: two levels **Weak fix — delegation ("Hide Delegate" refactoring):** ``` order.getCustomerCity() // Order asks Customer, Customer asks Address, ... ``` Each object exposes what the next one out needs and hides the hop. Coupling now goes one edge at a time. **Strong fix — Tell, Don't Ask:** Often the caller didn't want the city name at all; it wanted to *do* something with it. Instead of pulling data out, push the behaviour in: ``` order.printShippingLabel(printer) ``` Now no data is extracted, no chain exists, and the knowledge stays with the object that owns it. ### What LoD is not - It is **not** "one dot per line". Fluent builders (`builder.withA().withB().build()`) and collection/stream pipelines (`items.filter(...).map(...).sum()`) chain heavily and are usually fine, because each call returns the *same conceptual object* or a new value, not a deeper node of someone else's graph. - It is **not** free. Applied dogmatically it produces armies of pass-through wrapper methods (the "middle man" smell) — a real cost you must weigh. - It applies most strongly to **objects with behaviour**. Pure data structures / DTOs / configuration trees / parsed JSON deliberately expose structure; navigating them is their point. ### Rule of thumb Ask: *does this line depend on how another object is built internally, or only on what it can do?* If the former, you're likely violating LoD.

  • Does using a getter automatically violate the Law of Demeter?
    No. Calling a getter on an object you directly hold is fine. The violation is calling a method on the *result* of that getter — that result is a stranger you reached through your collaborator.
  • Why is 'mocks returning mocks' in a test considered evidence of an LoD violation?
    Because the code under test navigates a chain it doesn't own, so the test must reconstruct that chain. If the test only had to stub one direct collaborator, the production code would only be talking to friends.

You want cash from a shop customer. You don't reach into their pocket, pull out their wallet, and take a note from it — you ask the customer to pay. You depend on what they can do (pay), not on whether their money lives in a wallet, a phone, or a sock.

context

open as a page

State the formal Law of Demeter rule: which objects may a method M of an object O legitimately send messages to?

level: middleimportance: must knowfreq 42%

basics

~20 s

Method M of object O may call methods on: O itself, O's own fields/components, M's parameters, objects M creates inside itself, and globals in scope. It may not call methods on objects returned by those calls.

open as a page

Why is "count the dots on the line" a bad test for Law of Demeter violations? Give examples of long chains that are fine and short chains that are not.

level: middleimportance: should knowfreq 38%

basics

~10 s

Dots don't measure coupling. list.filter(...).map(...).count() has many dots but no new dependencies, while a.getB().doIt() has few dots yet reaches into a stranger. What matters is whether you're walking another object's structure.

open as a page

What does strict adherence to the Law of Demeter cost, and how do you decide when the wrapper/delegation overhead isn't worth paying?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Every hidden hop needs a pass-through method, so classes fill with delegating one-liners (the "middle man" smell), APIs get wider, and changes ripple through several files. It's worth paying when the hidden structure is genuinely likely to change.

open as a page

How does the Law of Demeter relate to "Tell, Don't Ask" and to the Feature Envy smell, and how do you refactor a train wreck without simply adding a delegating getter?

level: seniorimportance: should knowfreq 30%

basics

~20 s

A long getter chain usually means the caller is pulling data out to do work that belongs elsewhere (Feature Envy). Instead of adding another getter, move the operation into the object that owns the data — tell it what to do.

open as a page

How does the Law of Demeter generalise beyond single objects — to modules, packages, and service boundaries — and what are its known limitations at that scale?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

The same idea scales up: a module or service should depend only on its direct neighbours, not reach through them into their dependencies. Facades, aggregate roots, and anti-corruption layers are Law of Demeter applied at architectural scale.

open as a page