The Law of Demeter
Tags: programming
Published: 2022-08-31 15:41:13

---
title: The Law of Demeter
published: true
date: 2022-06-15 00:00:00 UTC
tags: programming
canonical_url: http://calebhearth.com/law-of-demeter
---

The Law of Demeter, simply stated, says that an object should not “reach through” its collaborators to access _their_ collaborators’ data, methods, or collaborators.

The name of the law [references](https://ccs.neu.edu/home/lieber/what-is-demeter.html) the name of the project the authors were coding when they coined it. The authors named the project “Demeter”, which itself is a reference to a hardware description language called “Zeus”. Demeter, the goddess of harvest and agriculture, is a sister of Zeus.

Perhaps the easiest way of describing how to _obey_ the Law of Demeter is to give an example of _disobeying_ it. Here, our Ranger accesses `dwarf.strength.modifier` and `dwarf.proficiencies.include?`, both of which are violations of the Law:

```
class Ranger
  def toss_dwarf(dwarf, location)
    dwarf_check = rand(20) + dwarf.strength.modifier + (dwarf.proficiencies.include?(:athletics) ? dwarf.proficiency_bonus : 0)
    ranger_check = strength.modifier + (proficiencies.include?(:athletics) ? proficiency_bonus : 0)
    if ranger_check > dwarf_check
      dwarf.location = location
    end
  end
end

```

The problem here is that Ranger has more knowledge of how Dwarves work than it would need to when using other approaches. This leads to the objects being tightly coupled, which may make refactoring (“simplifies modification”), [testing](https://blog.testdouble.com/posts/2022-06-01-mocking-callbacks/), and debugging (“simplifies complexity of programming”) more difficult.

Law of Demeter is also known as the Principle of Least Knowledge. The concept was first published as a [paper](https://www2.ccs.neu.edu/research/demeter/papers/law-of-demeter/oopsla88-law-of-demeter.pdf) presented by Karl J. Lieberherr, Ian Holland, and Arthur J. Riel:

> For all classes C, and for all methods M attached to C, all objects to which M sends a message must be instances of classes associated with the following classes:
> 
> 1. The argument classes of M (including C)
> 2. The instance variable classes of C
> 
> (Objects created by M, or by functions or methods which M calls, and objects in global variables are considered as arguments of M.)

Less formally and specific to object-oriented languages that use this syntax, only use one dot in methods.

`dwarf.strength.modifier` is not okay as we reach through dwarf to `strength` to get `modifier`.

`dwarf.strength` and `dwarf.strength_modifier` are no problem, as we only reach through dwarf to get `strength` and `strength_modifier`.

## Benefits of Law of Demeter

1. Makes refactoring easier when either collaborators or your system changes
2. Makes writing code easier: you limit how much you need to think about to your immediate collaborators’ APIs
3. Makes testing easier: mocking for isolation and constructing objects for integration is simpler when you only need to construct immediate collaborators

## Don’t break the law

There are good ways in Ruby to avoid this code smell.

### Delegate to prefixed methods

Rails has a shortcut to [delegate](https://api.rubyonrails.org/classes/Module.html#method-i-delegate) methods to collaborators, so Dwarf can do this to avoid a Demeter violation in Ranger:

```
class Dwarf
  delegate :modifier, to: :strength, prefix: true, allow_nil: true
end

```

Exposing `strength_modifier` on Dwarf’s API allows for refactoring that method to use a different internal implementation while retaining behavior. It also simplifies mocking the method for isolated testing.

### Tell, Don’t Ask

Rather than Ranger asking Dwarf about its attributes and skills to make a check, teach Dwarf to make the ability check itself and call it as `dwarf.make_athletics_check`.

```
class Dwarf
  def make_athletics_check
    athletics_bonus = if proficiencies.include?(:athletics)
      strength.modifier + proficiency_bonus
    else
      strength.modifier
    end
    rand(20) + athletics_bonus
  end
end

```

### Pass strength as an argument

You can technically satisfy this by passing `strength` into the method as it would then become acceptable to call `strength.modifier`. This is because `strength` would have become an argument to the method and would be acceptable to call methods on. Doing that probably wouldn’t fly in your pull request review in the above example because it contorts itself so much to follow the Law. If there were some constraint that prevented delegation or Tell, Don’t Ask, passing strength in could be an option. In this case, I would recommend that as a time to bend the Law instead of passing in `modifier`.

## Exceptions to the rule

Law of Demeter is about reaching through objects to their collaborators. As such there are some exceptions when we consider interacting with other design patterns.

### Builder pattern

The builder pattern, for example, expects significant method chaining and this type of chaining is not considered a violation of Demeter. An example with ActiveRecord’s Query Interface, which uses the builder pattern to build up SQL queries:

```
Dwarf
  .where(friend: ranger)
  .where(weapon: :axe)
  .first # object created by our method
  .name # one allowed method call
  .split(",") # .split and .first are Demeter violations
  .first

```

All of that through `.first` is using ActiveRecord’s query builder, so you can think of that all as creating a new object for purposes of this rule. The `.name` is our “one dot”, so `.split.first` is breaking the rule but up to that point nothing is wrong with the method chaining as far as Demeter is concerned.

In fact, as Law of Demeter is stated in terms of types, because `Dwarf.where` returns an `ActiveRecord::Relation` object, that becomes a type that we create ourselves. Any method returning an object of type `ActiveRecord::Relation` can be chained from, so the Builder pattern which returns modified objects of the same type is explicitly allowed by the Law of Demeter.

In practical terms, because we control the `Dwarf` object, we can define methods such as `name_parts` on it. In the method chain above, `.first` returns a `Dwarf`, so that is where we consider the Law of Demeter to begin to be enforced.

### Map/reduce

Another acceptable example would be `[].map {}.reduce {}`, a well-established pattern for manipulating data. The results of `map` and `reduce` fall into the “object you create” exception to the rule as each method returns a new object created by our method.

### Interacting with 3rd-party data or libraries

When consuming an API, you might find yourself needing to access deeply-nested data that your application isn’t creating on its own. For example to consume the [ArkhamDB API](https://arkhamdb.com/api/public/card/01001) for a popular card game, you might need to dig deeply to know what cards you can add to the deck with code like:

```
card_json["deck_options"].each do |opt|
  puts "#{opt["faction"]} (#{opt["level"]["min"]}–#{opt["level"]["max"]})"
end

```

In Ruby and other weakly-typed, object-oriented languages this type of chaining (remember that `.[]` is a method) is an acceptable exception to Law of Demeter. In strongly typed languages such as Go or Swift, you would probably create structured data objects to decode this JSON into and in that case you could define methods such as `card.factionOptions()` to remain within the Law.

You don’t always control the API surface a gem or library provides you. Sometimes you’ll need to break the Law of Demeter to interact with code that you don’t own, and that’s acceptable as well. A piece of advice I’ll offer here is that you may want to encapsulate third-party libraries and APIs into [Gateways](https://martinfowler.com/articles/gateway-pattern.html) that both provide a seam in your own code for faking and can encapsulate code that necessarily looks and acts differently than the rest of your system.

## Conform to the Law of Demeter, or don’t

The Law of Demeter points out _potential_ issues in your code. While strict adherence to the rule is an option, practicality and style might push you toward some violations of the Law. It’s okay to have a small number of such violations in a codebase, and you should feel free to break this “law” as you would any other best practice when it makes sense for your code. As Martin Fowler [puts it](https://twitter.com/martinfowler/status/1649793241?lang=en), a better name might be the “Occasionally Useful Suggestion of Demeter”.

If you do see method chaining, it should stand out as something to be second guessed and you should consider avoiding or refactoring that code, but feel free to consider and decide against it.