Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Design Principles  ›  Lesson

Law of Demeter and Tell, Don't Ask

Law of Demeter 15 minAn object should only talk to its close collaborators and should tell them what to do instead of pulling out their data to decide for them.

Law of Demeter and Tell, Don't Ask

Shelfwise's label printer contains order.customer.address.city. When customers were allowed several addresses, Customer.address became a list, and the label printer broke, though nobody had touched it. The printer knew too much about objects it had no business knowing. Two closely related principles keep objects from reaching through each other.

The rule

Talk only to your friends, and tell them what to do.

Law of Demeter (the "principle of least knowledge"). A method should only call methods on:

  • its own object (self),
  • its arguments,
  • objects it creates,
  • its own fields.

It should not reach through those to their insides. A chain like order.customer.address.city couples the printer to Order, Customer and Address all at once.

# Reaching through
city = order.customer.address.city

# Asking the friend
city = order.shipping_city()

Now only Order knows how a shipping city is found, and when addresses change, only Order changes.

Tell, Don't Ask. Do not pull data out of an object, make a decision, and push the result back in. Tell the object what you want, and let it decide using its own data.

# Asking, then deciding for it
if wallet.balance >= total:
    wallet.balance -= total
else:
    raise InsufficientFunds()

# Telling
wallet.pay(total)   # checks and subtracts inside

The asking version spreads the wallet's rule into every caller, and one caller that forgets the check can overdraw the wallet. The telling version keeps the rule inside, which is encapsulation in action.

A note on dots: the Law is about reaching through objects, not about counting dots. A fluent chain on one object, like text.strip().lower(), is fine, because each call returns a plain value you are working on, not a stranger's internals.

The shortcut

Scan a method for chains that walk into other objects' parts, and for get-then-decide-then-set patterns. For each chain, add a method to your direct friend. For each get-decide-set, move the decision into the object that owns the data.

Cleaning up the refund handlerStep 1 of 4
  1. Spot the chain

    order.payment.gateway.refund(order.payment.amount) walks through payment into gateway.

The trap is fixing a chain by adding pass-through wrappers everywhere (order.get_customer_address_city()). Ask what the caller actually needs, such as a shipping city or a label, and name that.

Drills

Answer fast — trust the rule.

quick drill

Which line breaks the Law of Demeter?

quick drill

What does Tell, Don't Ask recommend instead of if stock.count >= n: stock.count -= n?

quick drill

Why did the label printer break when Customer.address became a list?

quick drill

Which fix is best for order.customer.address.city in the label printer?

Remember

  • Talk only to your friends, and tell them what to do.
  • Scan for chains into other objects' parts and for get-decide-set; move each into the owner.
  • Trap: pass-through wrappers that copy the chain instead of naming the real need.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainShorten the chain

Shelfwise's label printer contains city = order.customer.address.city and elsewhere if order.customer.wallet.balance >= total: order.customer.wallet.balance -= total. Explain which principle each line breaks and rewrite them.