Eliminating Code Complexity by Finding Double Negatives

I have been reading “A Philosophy of Software Design,” and almost the entire book is spent either explaining the dangers of complexity in a codebase, or eliminating complexity.

Code, especially Ruby code, should make its intent loud and clear to the reader. Clear code is the opposite of complex code. It’s easy to understand its purpose, so it’s easier and less risky to modify, extend, or remove.

Double Negatives

One thing that I haven’t seen explicitly discussed in this book is double negatives.

Whether it’s spoken or written, double negatives make sentences less clear. Something like “There are not no eggs left at the store” is obviously poor grammar, but it also makes the sentence harder to understand.

When our code reads like a sentence (well written Ruby should), double negatives increase complexity. Things like unless !some_condition can be more clearly written as if some_condition.

Most programmers will find writing in-line conditionals like this to be straightforward, but it gets less intuitive when extracting this logic into methods.

An example

A bit ago, I was writing some ruby code with a friend. We wanted to take an action if something was false, and like the good ruby programmers we are, we extracted that complex conditional into its own short method.

We found ourselves going around and around trying to make this as clean as possible. One of our first iterations contained a programming double negative - see if you can find it:

# Method call
return [] unless items_found(users)


# Method implementation
def items_found(users)
  no_items_found = false
  users.each do |volunteer|
    if volunteer.items.present?
      no_items_found = true
    end
  end
  no_items_found 
end

Contrast this to what we ended up with

# Method call
return [] if no_items_found_for(users)


# Method implementation
def no_items_found_for(users)
  no_items_found = true
  users.each do |volunteer|
    if volunteer.items.present?
      no_items_found = false
    end
  end
  no_items_found 
end

It’s a pretty small change, but I think it highlights what the code actually does much better than the first time around. I’m trying to be more intentional about writing my code with these things in mind.