Throwing Medicine Balls - how constraints make you a better Programmer

30 Jan 2014

When I was still playing basketball, our coach used to let us practice with medicine balls. The ugly brown leather balls weighting a ton. At least they felt that way after the 10th shot.

At first I considered it as just another mean way to improve our fitness. It was not really likely to ever run out of normal basketballs with only medicine balls left to continue playing.

However, after a while I realized that practicing with medicine balls actually helped me become a better basketball player. I learned to adapt my passing and throwing technique to balls of different weights. This helped during long games, when I became tired and had less strength left. In these situations, a basketball felt actually more like a medicine ball. Thanks to my training I was used to this and I was still able to take a proper shot.

Ok, but what does throwing medicine balls have to do with programming?

Playing basketball with a medicine ball is an artificial constraint. Constraining ourselves during training forced us to focus on skills otherwise neglected.

The question is, what is the equivalent of training with medicine balls in programming?

One example is programming without conditional statements. Programming without conditionals is a similar artificial constraint. You most likely will never encounter situations in which you cannot use if statements.

Let's take a look at a simple example in ruby in which we want to print all cells in a game of life:

class Cell

  def initialize(alive)
    @alive = alive
  end

  def alive?
    @alive
  end

end

def print_world(*cells)
  cells.each do |cell|
    if cell.alive? 
      print 'x'
    else
      print ' '
    end
  end
end

print_world(Cell.new(true), Cell.new(false))

Now let's try to get rid of the if statement. We could, for example, replace the conditional with polymorphism. In our case it means to create a separate class for each cell state, where both classes provide different implementations for the to_s method:

class DeadCell

  def to_s
    ' '
  end

end

class AliveCell

  def to_s
    '*'
  end

end

def print_world(*cells)
  cells.each do |cell|
    print cell
  end
end

print_world(AliveCell.new, DeadCell.new)

Polymorphism not only helps us to get rid of the if statement, it also makes our code cleaner. It no longer violates the open/closed principle, as we are able to introduce new cell states without having to change the existing cell implementation.

A second possibility would be to use a map to store the mapping between cell states and their string representation:

serializers = {
  :alive => 'x',
  :dead  => ' '
}

If we wanted to support more sophisticated mappings, we could even use procedures as map values. Our cell implementation just needs a generic state, which we implement using a symbol:

class Cell

  def initialize(state)
    @state = state
  end

  def state?
    @state
  end

end

Printing the cells uses the mapping between cell states and their string representation:

def print_world(serializers, *cells)
  cells.each do |cell| 
    print serializers.fetch(cell.state)
  end
end

print_world(serializers, Cell.new(:alive), Cell.new(:dead))

This approach has the benefit that we can easily provide different string representation for the same cell state, as the to string mapping is no longer tied to the cell class. The last implementation is pretty much what is known as the strategy pattern.

Isn't this great? By simply avoiding conditional statements, we discovered and practiced two patterns, which can considerably improve code in our daily life.

I am not saying that everyone should stop using if statements. Instead, we should stop taking everything for granted and try new things. Like in sports, we need to train our skills to become better at what we do. Using artificial constraints is an effective way to focus on otherwise neglected skills. Even though it might not make much sense at first, it turns us into better programmers. Just like throwing medicine balls.