Keep your privates close

Harold Giménez

Private with unicorns

A problem with the way we declare private methods in Ruby is the fact that when a class gets larger and more private methods are added to it, we lose sight of whether we are looking at a private, protected or public method. This is because the private declaration is a few hundred lines above the method you are looking at. Some people use another level of indentation on private methods to loudly proclaim their privateness, but this just doesn’t do it for me. About half of us here at thoughtbot (ok, just a couple of us) prefer setting private methods explicitly by providing a symbol to the private call:

class Archive
  def import
    download
    decompress
    cleanup
  end

  def download
    # ...
  end
  private :download

  def decompress
    # ...
  end
  private :decompress

  def cleanup
    # ...
  end
  private :cleanup

  def another_public_method
    # doing really cool stuff
  end
end

The main advantage of this approach is that you always know the method’s visibility, not that it really matters in Ruby, but I digress. Some may say that it’s tedious to write, or that it clutters your class. If you believe that it is tedious to write, we have $EDITORs at our disposal.

Help me help you

Here’s what I did to make vim mark a method as private. Just place your cursor below a method, and type <Leader>p to privatize it:

function! Privatize()
  let priorMethod = PriorMethodDefinition()
  exec "normal iprivate :" . priorMethod  . "\<Esc>=="
endfunction

function! PriorMethodDefinition()
  let lineNumber = search('def', 'bn')
  let line       = getline(lineNumber)
  if line == 0
    echo "No prior method definition found"
  endif
  return matchlist(line, 'def \(\w\+\).*')[1]
endfunction

map <Leader>p :call Privatize()<CR>

But the advantages are twofold. For one, you always know if a method is private. It also helps clean up your code because it affords you the opportunity to decrease the vertical separation between the private method and the first time it is invoked. When you are reading a method that calls the private method, it is much easier to scroll a few lines down to see its definition (or just zt in vim) than it is to do a search for the method name, read the definition, and then come back to the context where it was called.

A familiar pattern

Vertical distance in code is not a new concept. For example, it is good form to always declare local variables as close as possible to their first use, increasing legibility and decreasing ambiguity. Similarly, when we write unit tests it is important to keep any setup or fixtures close to where you exercise the code, so that your assertions or examples have a clear context. If we follow this pattern elsewhere, sometimes unconsciously, why not follow it for private methods as well?