Search code examples
ruby-on-railsdesign-patternslanguage-agnosticlaw-of-demeter

Follow Law of Demeter when using collections?


Within Ruby on Rails (or any other language with a collection...) is it necessary to break Law of Demeter violations up when querying something simple like a count?

class Survey
  has_one :kingdom

  def first_survey?
    # Should this be broken according to Law of Demeter?
    self.kingdom.surveys.count == 1
    # -or-
    self.kingdom.surveys_count == 1
  end
end

class Kingdom
  has_many :surveys

  # Is this the "right thing to do", or overkill?
  def surveys_count
    self.surveys.count
  end
end

Solution

  • Usually when I see Law of Demeter violations the first question I ask isn't "How do I 'avoid a dot'?" The question you should ask is "Does this functionality that violates belong to someone else?" In this case I would probably structure it like so:

    class Survey
      belongs_to :kingdom
    end
    
    class Kingdom
      has_many :surveys
    
      def first_survey?(survey)
        surveys.first == survey
      end
    end
    
    kingdom = Kingdom.find(kingdom_id)
    first_survey = kingdom.surveys.first
    last_survey = kingdom.surveys.last # Assuming there is more than one survey.
    
    kingdom.first_survey?(first_survey) #=> true
    kingdom.first_survey?(last_survey)  #=> false
    

    By structuring it this way the Survey no longer has to reach into the Kingdom object and query its assocations, avoiding the Law of Demeter violation. This also allows you to change the definition of first_survey? later on. A contrived example would be if Surveys could be "published". The first_survey? for a Kingdom could then be easily changed to support only checking if the passed in Survey is the first Survey with the published attribute set to true.