Ruby Science

Extract Value Object

Value Objects are objects that represent a value (such as a dollar amount) rather than a unique, identifiable entity (such as a particular user).

Value objects often implement information derived from a primitive object, such as the dollars and cents from a float, or the user name and domain from an email string.

Uses

  • Prevent duplicated code from making the same observations of primitive objects throughout the code base.
  • Remove large classes by splitting out query methods associated with a particular variable.
  • Make the code easier to understand by fully encapsulating related logic into a single class, following the single responsibility principle.
  • Eliminate divergent change by extracting code related to an embedded semantic type.

Example

InvitationsController is bloated with methods and logic relating to parsing a string that contains a list of email addresses:

# app/controllers/invitations_controller.rb
def recipient_list
  @recipient_list ||= recipients.gsub(/\s+/, '').split(/[\n,;]+/)
end

def recipients
  params[][]
end

We can extract a new class to offload this responsibility:

# app/models/recipient_list.rb
class RecipientList
  include Enumerable

  def initialize(recipient_string)
    @recipient_string = recipient_string
  end

  def each(&block)
    recipients.each(&block)
  end

  def to_s
    @recipient_string
  end

  private

  def recipients
    @recipient_string.to_s.gsub(/\s+/, '').split(/[\n,;]+/)
  end
end
# app/controllers/invitations_controller.rb
def recipient_list
  @recipient_list ||= RecipientList.new(params[][])
end

Next Steps

  • Search the application for duplicated code related to the newly extracted class.
  • Value objects should be immutable. Make sure the extracted class doesn’t have any writer methods.

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.