Ruby Science

Feature Envy

Feature envy reveals a method (or method-to-be) that would work better on a different class.

Methods suffering from feature envy contain logic that is difficult to reuse because the logic is trapped within a method on the wrong class. These methods are also often private methods, which makes them unavailable to other classes. Moving the method (or the affected portion of a method) to a more appropriate class improves readability, makes the logic easier to reuse and reduces coupling.

Symptoms

  • Repeated references to the same object.
  • Parameters or local variables that are used more than methods and instance variables of the class in question.
  • Methods that include a class name in their own names (such as invite_user).
  • Private methods on the same class that accept the same parameter.
  • Law of Demeter violations.
  • Tell, don’t ask violations.

Example

# app/models/completion.rb
def score
  answers.inject(0) do |result, answer|
    question = answer.question
    result + question.score(answer.text)
  end
end

The answer local variable is used twice in the block: once to get its question, and once to get its text. This tells us that we can probably extract a new method and move it to the answer class.

Solutions

  • Extract method if only part of the method suffers from feature envy; then move the method.
  • Move method if the entire method suffers from feature envy.
  • Inline class if the envied class isn’t pulling its weight.

Prevention

Following the law of Demeter will prevent a lot of feature envy by limiting the dependencies of each method.

Following tell, don’t ask will prevent feature envy by avoiding unnecessary inspection of another object’s state.

Ruby Science

The canonical reference for writing fantastic Rails applications from authors who have created hundreds.

Work with us to make a new Rails app, or to maintain, improve, or scale your existing app.