How to program like an explorer (with Pry!).

Conrad Irwin — June 2012

Exploring is a large part of what programmers do during the time when we're not typing out code. Attempting to discover the correct way to do something, or to get a feeling for how something works is an essential part of the job, and for many people it's also the most fun.

While these aren't the only examples, I classify the following as exploring:

  1. Trying out new libraries.
  2. Designing good APIs.
  3. Debugging existing programs.
  4. Exploring data sets.

There are several passive ways to solve these tasks. You can try Google, and see if someone else has blogged about the problem, or try reading lots of existing code or documentation in the hope that inspiration strikes. A more active approach however is to write some code.

Exploring with code

Writing code to explore problem domains is the best way to get tangible feedback. If you're designing an API, but don't try using it, your API will not be very good. If you're trying to learn a new library, but don't actually use it, you'll not gain much. Finally, if you are trying to debug without writing code; you are trying to emulate an entire computer with your mind, which is pretty tiring.

The code you write while exploring will be different from the code you write when building applications. Instead of the aim being an application you can deploy, the aim is to improve your mental model. This in turn means that you need to treat code differently: good exploratory code is designed to be written quickly, run once, and to give you plenty of output that you can understand what happened. It's expected to be buggy, and you're expected to just keep adding hacks until it works.

Programming in a REPL

Read-evaluate-print loops are an invaluable tool for exploratory coding. They have features that are so obvious to enable this that you probably didn't notice them before:

  1. Intermediate values generated are always displayed.
  2. Running programs can be inspected in arbitrary detail.
  3. You can always decide which line of code to execute next.

Contrast this to a normal development cycle of using a text-editor and then running the program from the start. In that process the computer mindlessly re-evaluates the entire program, dumps out a tiny amount of information at any print statements you've inserted, and then exits, throwing away the entire state.

Using Pry as a REPL

Pry is a REPL designed with these features in mind. Taking inspiration from Smalltalk and SLIME, it embraces the idea of exploratory programming and helps you to do it more effectively. While it'd take me too long to cover all of its features, here are the two I consider most important:

ls


[1] pry(main)> ls CodeRay

constants: CODERAY_PATH Duo Encoders FileType GZip Plugin PluginHost Scanners Styles TokenKinds Tokens TokensProxy VERSION WordList
CodeRay.methods: coderay_path encode encode_file encode_tokens encoder get_scanner_options highlight highlight_file scan scan_file scanner

If you've ever wondered what a given object can do, the ls command will help you. Additionally, and along with the find-method command, it can also answer questions like "How do I use this API to achieve X?".

show-source


[2] pry(main)> $ binding.pry

def pry(*args)
  if args.first.is_a?(Hash) || args.length == 0
    args.unshift(self)
  end

  Pry.start(*args)
end

The show-source command, aliased to $, allows you to see how something is implemented. This is vital both for debugging, and also for exploring new libraries. The edit-method command can be used in combination to fix bugs you spot on the fly.

Summary

Acknowledging the existence of temporary exploratory code as distinct from permanent application code has huge benefits. When you're comfortable with writing code that will be immediately thrown away, you can iterate purposefully to find solutions instead of relying on google and inspiration.

A REPL is the best tool to help you do this. Unlike your text editor which is designed for writing permanent robust code, a REPL is designed to help you write temporary code to quickly understand problem domains. Exploration tasks where this is most helpful include learning new libraries, designing APIs, debugging, data analysis, smoke testing, etc.

Pry is a world-class REPL. It's written in Ruby, and due to its extensive wrapping of Ruby's introspection APIs excels for exploring in Ruby. Due to the JVM's homogeneous object model and JRuby we're also beginning to see Pry used as an exploration tool for non-ruby projects1.

And so that is why you should use Pry :).