Relative Sanity

a journal

Being expressive is a great way to reveal intention in your code, and a programming language like Ruby makes it hard to avoid being expressive. RSpec is often cited as a great example of an expressive DSL:

describe "addition" do
  it "sums two given values" do
   expect( 2 + 2 ).to eq(4)
  end
end

Now, there's some trickiness with the syntax if you don't read Ruby (where you need to put parentheses, periods, spaces, the odd do keywords etc), but anyone with a command of the English language can read that code and understand what it's supposed to do.

Better than that, they've got a good chance of being able to produce their own variations from the code, which rapidly reduces the barrier to entry.

Papers, please

Barriers don't just exist at the entry to a programming language, though. Consider this code:

class Checker
  def check(upl, rpl)
    upl < rpl ? pass_chk : fail_chk
  end
end

What's it doing? Well, it's certainly "checking" something, but what, and why? The code isn't very intention-revealing, meaning that we'd have to go and look at where it's being called (the client code) in order to get an idea of what is going on. We could make this code far clearer by writing something like:

class Checker
  def check(user_permission_level, required_permission_level)
    if user_permission_level < required_permission_level
      grant_permission
    else
      deny_permission
    end
  end
end

Yes, the code is longer, but it's far less ambiguous, meaning that a new coder on the project won't spend ages digging through a backtrace just to spot the (now painfully obvious) bug.

So expressive code isn't just fun to write, it can make code easier to understand, easier to reason about, and harder to get wrong.

Which brings me to one of my favourite conventions in Ruby: predicate method naming.

Ruby, eh?

Predicate methods are questions, expected to return a boolean. In Ruby, they are conventionally phrased as a question, and terminated with a question mark:

7.even?
current_user.is_admin?

Thanks to Avdi, I now read the above as "seven even, eh?" and "current user is admin, eh?"

(It's not always obvious, but question marks in Ruby method names are purely syntactic sugar. Ruby doesn't check that ? methods return booleans — it's just a convention that they do)

Where predicates take arguments, it's common to phrase the "question" of the method as it would be phrased if it included the argument as the subject of the question, for example:

current_user.has_permission_level? 7

which conventionally reads as "current user has permission level 7, eh?"

As you code Ruby, you'll notice some variance in how "sentence-like" to make predicate methods. Which of these is most "Ruby-ish"?

user.is_admin?
user.admin?
user.is_an_admin?

Ruby lore says that those of you who passionately cried is_admin? are Java refugees, but in my experience, I haven't come across a better answer than "it depends on how widely used you expect the method to be".

Entropy increases

A rule of thumb I have is to assume code will "degrade" over time. Methods you wrote for specific cases will be used in ways you didn't expect; objects will grow arms and legs and barnacles and responsibilities over time; data structures will have values bolted on to them that shouldn't strictly be there, but aid performance; In short, your code will weather, and like any structure, it helps if you can build it to improve with age, instead of falling apart.

Style guides are often very useful in helping teams to produce weather-resistant code, and I'll talk about that in the future, but right now let's consider the specifics of predicate methods.

The is_…? variations would seem, at first glance, to be preferable. They read far more easily: "user is admin, eh?" versus "user admin, eh?", with "user is an admin, eh?" perhaps feeling like the pinnacle of expressiveness. But let's consider we add the ability to group users using something like ActiveRecord:

our_users = current_company.users

We now want to narrow our interest only to users which are administrators:

our_users.select { |u| u.is_admin? }

This is fine, and perfectly readable, but Ruby provides us with a shortcut when we have a block that simply returns the same method call from each of the objects handed to it:

our_users.select &:is_admin?

To me, this reads a little awkwardly — our original intention was to select only "users which are administrators", not "users which is administrators", but that's where we've ended up.

Now to be sure, we could (and probably should) go and do this properly so we can simply say:

current_company.administrators

but in some cases this may not be practical, and so we put up with the slight awkwardness. The problem with that is that "putting up with slight awkwardness" is a comparative decision. It's only getting "slightly worse" this time, but next time it's worse than this time, and the time after that even more so.

Making decisions like this is often the right, pragmatic thing to do, but sometimes it's not a conscious decision at all, just a series of "it's clear enough, let's move on" non-decisions. That's how we end up with a < b ? do_success : do_fail bugs.

One way to avoid this is to start out making method names as small as they can be without losing their expressiveness. This has the double-whammy of also encouraging methods themselves to be small.

Taking a cue from human languages, comparability helps immensely here. "is admin, eh?" and "are admins, eh?" are two separate phrases, but they both "mean" the same thing. The difference is in the context of the question. Knowing this, we can understand the difference between what's intrinsic to the question itself ("admin, eh?") and what's intrinsic to the context "user is", "users are". Focussing on what's intrinsic to the question when naming predicate methods allows us to decide what can be thrown away, since it can be inferred by our minds from the context:

current_user.admin?
our_users.select &:admin?

Sure, current_user.is_admin? sounds "better" in many ways, but our_users.select &:is_admin? sounds way worse, since our minds are far better at filling in gaps than resolving dissonance.

It depends

This is all a matter of taste, which is one of the reasons that it's important to establish what you're going to as a team, and then to stick to it, even if you disagree with it personally. The whole point here is to be understandable. Languages like Ruby really do allow us to be incredibly expressive in our code, but like any form of expression, the more individual our expression, the more likely we are to be misunderstood.

Programming gives us a chance to bridge that gap — to invent incredible new ways to solve old problems, but as programming becomes more and more like our everyday discourse, unless we're careful, we can end up bringing a lot of the old problems right along with us.