In Progress
Unit 1, Lesson 21
In Progress

Plural Name

Video transcript & code

From time to time I like to do episodes about naming things. Today I want to quickly discuss a small variable naming guideline that can make your code more clear, and help reduce mistakes.

Let's say we've got a class that represents a Zoo.

Let's go ahead and create an instance, and stock it with some animals.

Zoo = Struct.new(:animals)

triassic_park = Zoo.new(["Hyperodapedon",
                         "Smilosuchus",
                         "Typothorax",
                         "Eoraptor"])

A good zoo needs to enforce some rules. Let's write a method to warn people about feeding the animals.

Zoo = Struct.new do
  def warn
    animals.each do |animal|
      puts "Please do not feed the #{animals}"
    end
  end
end

Quickly now: what's wrong with this code?

Too slow! Let's run it.

triassic_park.warn

# >> Please do not feed the ["Hyperodapedon", "Smilosuchus", "Typothorax", "Eoraptor"]
# >> Please do not feed the ["Hyperodapedon", "Smilosuchus", "Typothorax", "Eoraptor"]
# >> Please do not feed the ["Hyperodapedon", "Smilosuchus", "Typothorax", "Eoraptor"]
# >> Please do not feed the ["Hyperodapedon", "Smilosuchus", "Typothorax", "Eoraptor"]

See what we did wrong? We interpolated the variable animals where we should have interpolated animal.

Chances are we didn't even write out the wrong variable ourselves. We probably hit autocomplete and the editor filled it in for us.

This code violates a naming guideline I learned years ago: never give two nearby variables names that differ by only a single character.

Now, there are a few different ways we could fix this code to comply with the guideline.

One common way to differentiate variables in a case like this is to use a shorthand name for the shorter-lived variable.

Zoo = Struct.new(:animals) do
  def warn
    animals.each do |a|
      puts "Please do not feed the #{a}"
    end
  end
end

I've been known to use this technique. But I'm not really happy with it. The more code we add to this loop, the less obvious it's going to be what a is short for. And if we ever factor a new method out of the loop body, the shortened name will be even less justified.

Instead of altering the singular variable name, in cases like this I've tried to make a habit of altering the name of the plural variable. But what will we call the animals attribute, other than animals?

Well, this one comes down to a matter of taste. But personally, when no better name suggests itself I use a convention of appending the word list. Like this.

Now, anytime we need to refer to singular animals, we can just use the obvious variable name animal, instead of trying to come up with a variation that doesn't violate the single-character-difference rule.

Zoo = Struct.new(:animal_list) do
  def warn
    animal_list.each do |animal|
      puts "Please do not feed the #{animal}"
    end
  end
end

I like the term list, because it suggests the basic shape of the data, without implying a specific Ruby data type like Array or Set.

But as I said, I use this convention when no other name jumps out at me. And one thing I've found is that once I start to think about the naming of some collection of things, often a more domain-appropriate term will suggest itself. In this particular case, right after I wrote this example code I took a break for lunch.

When I came back, it immediately occurred to me to rename this collection to "managerie".

Zoo = Struct.new(:menagerie) do
  def warn
    menagerie.each do |animal|
      puts "Please do not feed the #{animal}"
    end
  end
end

I'm always happy when this happens. Now, if we ever find we need to change this collection from a "dumb" array into a smart collection like the one we saw in episode #321, we have a ready-made name for that new class.

And that's all for today. Happy hacking!

Responses