Yield Thought

it's not as hard as you think
formerly coderoom.wordpress.com

I’ve been bored at work for many reasons at many different times, but three things stand out as real killers:

  1. working on the same project with the same people[1] for years and years,
  2. using the same old languages and tools (statically-typed: yuk!) instead of the new hotness,
  3. being forced to work on maintenance instead of new features, or on small parts of an existing product instead of creating something new.

These are the symptoms of a problem, not the cause, and I think most jobs will have elements of them. But surprisingly it turns out that - for programmers at least - boredom is a choice. Recently, I chose not to be bored. I chose to think one abstraction level higher. I chose to play the metagame.

Awesome copper comic

Me: a case study

I started thinking about programmer performance a while ago. Everybody will tell you that you can’t measure programmer productivity, but this is at best a half-truth. We can, and we should. Perhaps what we shouldn’t do is use those measurements to compare programmers to each other, but we can definitely measure ourselves.

When I started trying to measure my own productivity, it g

ot me thinking a lot more about:

  1. my workflow - I check email, pick a tracker ticket and work on it.
  2. the most repetitive parts of my work - why does it take 10 clicks and 3 windows to commit a change?
  3. the core of my job - I’m paid to solve non-trivial problems, not to sort email and adjust ticket priorities.

It really doesn’t matter what anyone’s day job is; whether you’re working on sporting result clips for Google mobile or maintaining a 20-year old internal accountancy package the metagame is the same. The product may be pointless but the metagame matters to us all. It’s about:

  1. surrounding ourselves with tools and systems that make us more than human, a cyborg-like super-programmer - who doesn’t want that?
  2. automating away the boring parts of work, so that we’re left with the interesting, non-trivial decisions and problems.

When I started I was working on bugfixing before a major release, which is very amenable to this sort of thing because there are lots of small, well-defined packets of work. We were about 9 weeks from release and my typical day looked like this:

  1. Check and respond to my emails
  2. Check the test machines and fix any system or build failures
  3. Take a high-priority bug from our tracking system
  4. Try to reproduce it locally
  5. Track down the cause and write a fix
  6. Commit the fix, update the ChangeLog, resolve the ticket
  7. Repeat from step 3

It was quite easy to measure my own performance in terms of the number of bugs resolved per week. Sure, it’s not a perfect measurement - I could also have factored in the priority of the bugs and so on, but getting an accurate figure wasn’t nearly as important as getting some measure, however rough.

With the goal of increasing my rate of bug fixes motivating me, I started laying into my workflow and adding automation wherever I found an opportunity to speed things up:

1. Don’t waste clicks navigating email

Email checking was clearly not related to my core metric (bugs fixed) but I couldn’t just ignore emails, however much I wanted like to. Instead, I added a bunch of extra filters to brutally cull all the emails I didn’t really need to read, then found out how to get keyboard shortcuts working in Gmail (hint: add &kbd=1 to the URL). Now I was whipping through the emails by pressing [ to read-and-archive for 95% of them, occasionally opening extra tabs to remind me of various actions I needed to take later in the day.

2. Don’t type ChangeLog entries by hand

Next up was the ChangeLog. I don’t know if you keep a ChangeLog at work, but we have done for a while. The idea is that with each commit you log the broad reason for the change, then write a one-liner for each function you’ve changed, along with the filename, class and method. Writing these by hand was incredibly tedious. Rather than dump it altogether (for it had its uses) I invested a few hours in writing a 147-line python script that generated the entry stubs automatically with inline diffs for each function changed. I added a handful of vim bindings to jump between the ChangeLog entries and replace each diff with a one-line description of it’s purpose. Suddenly, writing ChangeLogs was ten times faster even somewhat fun.

3. Yes, I said Vim

It’s no coincidence that I started using MacVim shortly before my metagame trip. Vim is awesome for exactly one reason:

  1. A vim script is exactly the same as the keypresses you use when editing

Writing a script in vim is a simply matter of typing the same characters you normally would to achieve that effect (which is why using hjkl for movement isn’t as stupid as you thought it was). I cannot imagine a lower barrier to customizing your editor. The end result is that vim makes it trivial to optimize all sorts of little common operations; it’s the first editor whose macro functionality I’ve used on a daily basis. It’ll change your life. Learn it. Love it. It’s worth it.

4. Make reproducing bugs trivial

My previous attempt to make my job more interesting had been to volunteer to rewrite our clunky, frustrating GUI-click based test system with a new, streamlined one. Since we use Qt, I added a QScriptEngine which essentially lets you write a small C++ API for your application and then call that from javascript files.

This was a lot faster and less error-prone than manually baby-sitting fragile GUI-based testing as we’d done before, but the real benefit was that I had complete control over the system. Every night it ran tests across dozens of platforms and reported any new failures directly to our tracking system. I started adding extra code to our test-runner (a 1,500 line python script) to make reproducing and fixing bugs stupidly easy. Each test report now includes:

  1. the stack trace and variables for any segfaults
  2. the core files for any segfaults in external programs during the run
  3. all log files, stdout and stderr
  4. screenshots of the GUI should a test timeout
  5. a one-line, copy-and-paste command to re-run the test

Adding this one piece at a time wasn’t a lot of work, but it has saved us hours and hours and hours.

5. Add ssh and bash shortcuts

I spend a lot of time on our test machines, so I added hostname auto-complete to my bash shell, added single-line aliases to change to the test directory, check out an overnight build, view the build and test logs, change to the test user and so on. I learned to love .ssh/config, and so should you.

Saving a few keypresses doesn’t sound like a big deal, but it makes me happy every day when I type:

cs
smoketest -kri 14956

to switch to the latest test directory, update its license file and re-run the bug reported in ticket 14956. I could write an essay just on this:

every single element of cognitive burden removed makes it easier to stay focused on the task in hand

Not having to remember a hostname, or a compiler directory, or keep track of which system I’m on, streamlining all that away makes it trivial to keep thinking about the problem and not the distractions.

Vim!

6. You can’t have too much Vim

I ended up adding lots of vim shortcuts specific to our systems. It’ll look up and fill in the title of any bug ticket for me. It’ll commit my current changes, automatically taking the ChangeLog entry I just wrote as the commit message and optionally resolve the bug ticket associated with that change using the same message. In one command.

Typing that one feels really good.

Bundling up all the points at which I’d otherwise have to switch to a browser, wait for a page to load, this was accidental but brilliant. Waiting is the death of focus. By wrapping it all together into one fire-and-forget command, I can just say the word and then start choosing the next bug to fix, keeping my momentum and focus intact.

I’m not done

Every week I find new places to tweak my setup or semi-automate more tasks. I’ve started producing beautifully-formatted HTML change diffs for code review on my iPhone, while reclining in one of Combinat56’s Sumo bags with a cup of tea. I’ve added extra notifications when a build fails or a test machine runs out of disk space.

I will never be done, because I can always keep moving one abstraction higher until I’m purely working on the most interesting problem of all: how much of a programmer’s job can be automated?

A nice side-benefit is that much of the code I write to automate things is not production code; I can write it however I like, using whichever languages and tools take my fancy. Yet it all goes towards making me - one day - into an extraordinary programmer.

Playing the metagame: advice

After working like this for six months or so, the following pieces of advice seem like the most important to remember:

  1. Don’t be afraid. Spend time improving your efficiency instead of hacking away with a blunt axe. There can be a lot of pressure “just to finish this first”. Resist it. Take just one hour and use it to write a script to help you in some simple way, or improve your bash aliases, or your ssh config, or your mail filters. Once you’ve seen how much impact it makes, you’ll feel a lot better about doing it again.
  2. Semi-automation is better than full-automation. It’s easy to get carried away and try to write your own email client, or use bayesian filtering to answer all your emails. Don’t bother. Write the simplest, smallest thing you can to speed you up and then get back to work. If it helps, you’ll find yourself building on it naturally over time. It’s better to have one-key read-and-archive than a custom email client for your iPhone.
  3. Keep scripts specific. Don’t try to over-generalize them and solve everybody’s problem; that’s not going to be practical on the side. Make your scripts specific to you and your workflow. If they’re great, you can extend them to the team. If they love it, you can extend it to the world and put it on GitHub. But do it in that order.
  4. Use vim. It feels weird at first. It takes a couple of days to get used to. Set it up with nice plugins and themes right away; after a couple of weeks you’ll never look back.
  5. Optimize the things you hate, not the things you love. The goal is to build up scripts, commands and systems that feed you a flow of meaningful decisions to make and interesting problems to solve, while automating away the dross. Resist the temptation to start by optimizing programming or code-writing; attack all the distractions first.
  6. Never let yourself wait for something. If you catch yourself typing a command then waiting for it to finish before you can type the next one, then that’s an ideal place for a script. Waiting will kill you; make the computer wait for you. For some tasks, like compiling, write scripts that’ll automatically launch the program when compiling finishes, perhaps even re-running the test case if possible. Make your computer notify you when it’s ready, audibly or by throwing something up on the screen. In the meantime, you can be reviewing code or looking for a second bug to start work on, or taking a walk with a cup of tea. Anything but HN and Reddit!
  7. Write in all the fun languages you can’t use at work. I can’t recommend python enough for this sort of thing, as it’s huge supply of libraries combined with pleasant syntax make life a breeze. I guess Perl would be great too. But get used calling external programs and input / output streams and you can write in Node.js or whatever interests you most this week.
  8. Measure your performance. Write a simple script to measure the number of commits you’ve made. Or the number of lines you’ve changed. Or the number of bugs you’ve fixed. Or the number of customers you’ve helped. Just pick something that’s trivial to measure even if it’s far from perfect, and start. Add more things whenever you’re afraid you’re over-optimizing or gaming the measurements you’ve got so far. Seeing your own performance climb gives a real sense of satisfaction that might be otherwise missing in your daily work. Even if you don’t enjoy or value the internal actuarial calculator you’re writing, you should care deeply about making yourself a better programmer - this will stay with you your entire career.

That’s it - print this list out, stick it next to your monitor then close the browser and start playing the metagame! You weren’t going to do anything more productive in the next hour anyway, right? ;-)

Update: just in case you’re not heading off to work, the HN thread is here and the Reddit thread is here.

[1] Disclaimer: I work with absolutely first rate programmers, people I learn from every day and yet there’s still an attraction to meeting new people too; I shudder to think what it must be like to work with dull people for years and years…

Blog comments powered by Disqus