WorkspaceLow-Level Design
← Course overview

Course navigation

On this page

Low-Level Design / Design Principles

foundation · 12 MIN READ

Law of Demeter

A caller should talk to its immediate collaborators through meaningful operations rather than navigate their internal object graphs. This reduces how many structural details one change can break.

Reading completion is independent of quizzes and challenges.

What you’ll understand

  • A caller should talk to its immediate collaborators through meaningful operations rather than navigate their internal object graphs. This reduces how many structural details one change can break.
  • Customer.shippingCity hides address traversal behind the operation the caller actually needs.
  • Evaluate the tradeoff: Delegating every tiny field can create noisy forwarding methods. Prefer operations named for a real caller need, and distinguish domain objects from intentionally transparent data-transfer records.

Useful first: Classes and Objects

The idea and when to recognize it

A caller should talk to its immediate collaborators through meaningful operations rather than navigate their internal object graphs. This reduces how many structural details one change can break.

  • Requirement: A dispatch screen needs a customer’s shipping city. The customer record can be stored in either an old or a new layout.
  • Change to anticipate: Keep dispatch behavior stable when the customer’s internal address representation changes.
  • Design goal: Customer.shippingCity hides address traversal behind the operation the caller actually needs.

Start with the concrete problem

A dispatch screen needs a customer’s shipping city. The customer record can be stored in either an old or a new layout.

Keep dispatch behavior stable when the customer’s internal address representation changes.

Direct implementationRevised design
Reaching through customer.profile.address.city couples dispatch to several internal structures.Customer.shippingCity hides address traversal behind the operation the caller actually needs.
The baseline case can hide the problem. Compare the extension and boundary fixtures before accepting this design.Delegating every tiny field can create noisy forwarding methods. Prefer operations named for a real caller need, and distinguish domain objects from intentionally transparent data-transfer records.

Responsibilities and contracts

Customer.shippingCity hides address traversal behind the operation the caller actually needs.

  • Dispatch: Needs a city, not an address layout. Public operations: label(customer)
  • Customer: Hides address storage. Public operations: shippingCity()

Read the design

Select a participant to inspect its responsibility and public operations. Follow the labeled relationships; an arrow indicates direction, while the legend distinguishes ownership, substitution, and temporary use.

Preparing the design walkthrough…

Follow the interaction

Choose a supplied workload and compare the direct and revised implementations. Step through the same operation in both languages. Object values are recorded after each highlighted statement; previous steps remain unchanged.

Preparing the design walkthrough…

Implementation and expected output

Read the complete example alongside its input and expected output. The implementation selector changes the displayed program; the language selector preserves your current scenario and playback position.

Preparing the design walkthrough…

Try the idea in another setting

A booking service can ask inventory.reserve(item) instead of mutating inventory.warehouse.shelf.items directly.

  • Name the new client contract before adapting the example.
  • Identify which state belongs to each object and who controls its lifetime.
  • Write one normal case and one boundary case before extending the design.

Tradeoffs and interview takeaways

Delegating every tiny field can create noisy forwarding methods. Prefer operations named for a real caller need, and distinguish domain objects from intentionally transparent data-transfer records.

Common mistake: Reaching through customer.profile.address.city couples dispatch to several internal structures.

  • Explain the choice: Customer.shippingCity hides address traversal behind the operation the caller actually needs.
  • Challenge your choice: Delegating every tiny field can create noisy forwarding methods. Prefer operations named for a real caller need, and distinguish domain objects from intentionally transparent data-transfer records.
  • Describe a requirement that would make the simpler implementation sufficient.

Design challenge and knowledge check

Preparing the design walkthrough…

Make it your own

Saved on this device · 0/20,000

Reading completion is independent of quizzes and challenges.