Search code examples
ruby-on-railslaw-of-demeter

Law of Demeter - how far do you go?


I want to follow the Law of Demeter. As I am going through my code searching for the "two dots", I find myself asking if it's really worth setting up the delegation responsibilities in this type of context:

FROM

class Activity
  def increment_user_points!
    self.user.increment_points!(points, true)
  end
end

TO

module UserDelegator
  def user_increment_points!(points, increment_credits=false)
    self.user.increment_points!(points, increment_credits)
  end
end

class Activity
  include UserDelegator

  def increment_user_points!
    user_increment_points!(points, true)
  end
end

What are your thoughts?


Solution

  • Your example is not breaking the Law of Demeter. The user is an attribute of the activity and you are accessing a public API method on the user, so you are not in error with the original implementation.

    The goal of the Law of Demeter is to avoid breaking object encapsulation. Your "two dots" approach is somewhat of an oversimplification of the idea. In reality, you should examine how your objects are interacting and ensure that you are not reading too far into the attributes or relationships of other objects. For instance, if the following would be a violation of the rule:

    def update_user_address
      @user.address.set(new_address)
    end
    

    This would be due to the fact that the address is the business of the user, and it should encapsulate access to it appropriately through the user's API. As a client of the user, we should never directly have access to the API's of the users attributes.

    Again, in your example, you are using the users API directly, which is fine and is not violating Demeters Law. All that said, I have found the general rule to be a good one to follow. Your code will generally be easier to change and maintain and classes will be easier to refactor if you avoid breaking object encapsulation as shown.