Law of Demeter

The Law of Demeter was developed at Northeastern University. It’s named after the Demeter Project, which is itself named after Demeter, the Greek goddess of the harvest. There is widespread disagreement as to its pronunciation, but the correct pronunciation emphasizes the second syllable; you can trust us on that.

This principle states that:

A method of an object should invoke only the methods of the following kinds of objects:

  1. itself
  2. its parameters
  3. any objects it creates/instantiates
  4. its direct component objects

Like many principles, the Law of Demeter is an attempt to help developers manage dependencies. The law restricts how deeply a method can reach into another object’s dependency graph, preventing any one method from becoming tightly coupled to another object’s structure.

Multiple Dots

The most obvious violation of the Law of Demeter is “multiple dots”, meaning a chain of methods being invoked on each others’ return values.

Eg:

class User
	def discounted_plan_price(discount_code)
		coupon = Coupon.new(discount_code)
		coupon.discount(account.plan.price)
	end 
end

account.plan.price violates the Law of Demeter. The price method is not a method on User, its parameter discount_code, its instantiated object coupon, or its direct component account.

Refactored:

class User
  def discounted_plan_price(discount_code)
    account.discounted_plan_price(discount_code)
  end
end
 
class Account
  def discounted_plan_price(discount_code)
    coupon = Coupon.new(discount_code)
    coupon.discount(plan.price)
  end
end

in Rails, we can delegate

class User
	delegate :discounted_plan_price, to: :account
end

Multiple Assignments

Law of Demeter violations are often hidden behind multiple assignments.

class User
  def discounted_plan_price(discount_code)
    coupon = Coupon.new(discount_code) 
    plan = account.plan 
    coupon.discount(plan.price)
  end 
end

The Spirit of the Law

TODO

Objects vs Types

TODO

Duplication

The Law of Demeter is related to the DRY principle, in that Law of Demeter violations frequently duplicate knowledge of dependencies.

class CreditCardsController < ApplicationController
  def charge_for_plan
    if current_user.account.credit_card.valid?
      price = current_user.account.plan.price
      current_user.account.credit_card.charge price
    end
  end
end

In this example, the knowledge that a user has a credit card through its account is duplicated. That knowledge is declared somewhere in the User and Account classes when the relationship is defined, and then knowledge of it spreads to two more locations in charge_for_plan.

Like most duplication, each instance isn’t too harmful, but in aggregate, dupli- cation will make refactoring slowly become impossible.