Software Design

The Law of Demeter: When Method Chaining Becomes Bad Code

During code reviews, you’ve probably received feedback like this at least once.

4 min read
Cover image for The Law of Demeter: When Method Chaining Becomes Bad Code

During code reviews, you’ve probably received feedback like this at least once.

“There are too many dots (.) on this line.”

Writing everything continuously on one line can look cleaner, so what’s the problem?

The key to this discussion is the Law of Demeter.

Today, I’ll explain what the Law of Demeter is and, with examples, why some method chaining is fine while other chaining becomes bad code.

Let me start with the conclusion.

The Law of Demeter is the rule: “Don’t talk to strangers.”

Method chaining itself isn’t bad; it becomes bad code when you use chaining to reach into someone else’s internals.

Remembering this one sentence gives you half of today’s article.


What Is the Law of Demeter?

The Law of Demeter is also called the “principle of least knowledge.”

In simple terms:

An object should communicate only with its “close friends”—the things it knows directly.

Problems begin when you start using a friend’s friend, and then another friend of that friend.

The objects you can typically call from within a method can be summarized as follows.

  • Methods on itself (self)
  • Objects passed as the method’s parameters
  • Objects created directly inside the method
  • Property (member) objects it holds

The idea is to communicate only within this scope.

This is where the famous heuristic “one dot per line” comes from.

Of course, the number of dots is only a hint, not an absolute rule.


Why Can Method Chaining Become Bad Code?

Let me show you with code I actually encountered.

The situation was retrieving a customer’s city name from an order.

// Drill all the way from order → customer → address → city
let city = order.customer
                .address
                .city
                .name

It looks clean at first glance, right?

But this one line means that Order knows all about Customer’s internals, the Address inside it, and the City inside that.

This is where the problem appears.

If the Address structure changes or City disappears, this code collapses along with it.

You’re reaching into someone else’s drawers, so your code breaks when the structure of that house changes.

This kind of chaining down an object graph is commonly called a “train wreck.”

Train-wreck chaining linked together like train cars
Train-wreck chaining linked together like train cars

Because it looks like train cars connected one after another.

This line, with dots connected one after another, is a train wreck
This line, with dots connected one after another, is a train wreck

So How Do You Distinguish Good Chaining from Bad Chaining?

This is the most important part of today’s article.

Not all method chaining is bad.

There is one criterion.

“Does the chaining keep extracting and using other objects’ internals?”

As in the earlier example, repeatedly drilling into different objects—customer → address → city—is a violation.

By contrast, chaining that handles the same kind of subject and keeps returning itself, as below, is fine.

// filter·map Because chaining returns the “same context” each time, it is not a violation
let names = users
    .filter { $0.isActive }
    .map(\.name)

Higher-order function chaining and builder patterns don’t rummage through other objects’ internals, no matter how many dots they contain.

They simply return themselves—the same flow—each time and continue.

Comparing the two kinds of code in a table gives us this summary.

Category Bad chaining Good chaining
Subject Keeps extracting other objects’ internals Returns the same flow/type
Example order.customer.address filter { }.map { }
Coupling High (vulnerable to structural changes) Low
Assessment Violates the Law of Demeter Not a violation

How to Fix Violating Code

The solution is simpler than you might think.

Think of “Tell, Don’t Ask.”

Instead of extracting the internals, ask the object to do the work.

For the earlier city example, you can change it like this.

// OrderAsk for only the result you need
let city = order.shippingCity
Don’t ask; tell it what to do—one line like this is enough
Don’t ask; tell it what to do—one line like this is enough

Make Order traverse Customer and Address internally and return the city for you.

This way, the code outside remains intact even if the Address structure changes.

The scope of the changes stays neatly contained within Order.

After refactoring code this way myself, I found that the number of places to touch when changing the structure later was greatly reduced.


To summarize:

The Law of Demeter isn’t a rule about counting dots; it means not reaching into other objects’ internals carelessly.

When you encounter long chaining next time, ask yourself just one thing.

“Am I opening someone else’s drawer?”

Even asking this one question can make your code much cleaner.