It’s a UNIX system,
I know this!

by George Brocklehurst (@georgebrock)

I work for thoughtbot

Presented at dotRB,

Jurassic Park

Photo of Lex

There's a famous scene in Jurassic Park, where Lex sits down at a computer she's never used before, recognises it's UNIX, and quickly figures out how to use the system to lock the door.

It's a great scene, but is it realistic? Can we make interfaces so good that they're discoverable and familiar to people who've never used them before, with UNIX as the common ground?

Maybe we can, if we follow the conventions and obey the rules.

Conventions

Conventions are about what the user expects, but are not enforced by the technology we use. For example, most websites have a logo in the top left corner which links to the homepage.

Rules

Rules govern how software interacts with other software. By playing well with other software we can lean on a well known common interface (like a web browser, or a shell) and provide a more familiar experience.

Demo

The Greeter library provides one class, with one method. We are going to write a command line interface for it.

irb > Greeter.greeting "George"
 => "Hello George"
irb > Greeter.greeting "!!!"
Greeter::BadNameError: "!!!" is not a valid name

The simplest implementation

We begin with a simple implementation: 4e1f5c8

$ greet George
Hello George

Handling errors

This implementation handles errors badly. If we give bad input, we see a Ruby stack trace as output.

$ greet ...
/code/greeter/lib/greeter.rb:18:in `greeting': "..." is not a valid name (Greeter::BadNameError)
        from /code/greeter/lib/greeter.rb:7:in `greeting'
        from /code/greeter/lib/greeter/cli.rb:10:in `run'
        from /code/greeter/bin/greet:5:in `<main>'

We improve the implementation by adding error handling: 7c779c1

$ greet ...
greet: Error: "..." is not a valid name

Usage messages

Running the command with no input produces an error, which goes against the UNIX convention of providing a usage message.

$ greet
greet: Error: nil is not a valid name

We improve the implementation by adding a usage message: 9813de9

$ greet
usage: greet name

Output streams

The command does not play well with other commands, for example sending the output to a file is fine for good input but gives unexpected results for bad input:

$ greet George > out.txt
$ cat out.txt
Hello George
$ greet > out.txt
$ cat out.txt
usage: greet name
$

We improve the implementation by using the correct output streams: 0a74009

$ greet > out.txt
usage: greet name
$ cat out.txt
$

Exit statuses

The command does not play well with conditional execution.

$ greet George && echo Welcome
Hello George
Welcome
$ greet && echo Welcome
usage: greet name
Welcome
$

We improve the implementation by using non-zero exit statuses: c0b2ec2

$ greet && echo Welcome
usage: greet name
$ echo $?
64

Manual pages

The command is not documentated.

We improve the implementation by adding a manual page: 3fe6108

Distributing man pages with Rubygems is difficult, because gems are intended to be for libraries not applications.

Any questions?

Ask now, or later: @georgebrock on Twitter or email george@thoughtbot.com

I work for thoughtbot

Get 20% off at learn.thoughtbot.com
with the code DOTRB13