Rocking the Whiteboard

I used to tour a workshop on technical interviewing around the Bay Area developer bootcamps that begins with a short, apparently innocuous exercise:

Take five minutes to write a short program that shuffles a deck of cards.

If I got lucky with a few participants meeting bootcamp rigor with enough caffeine in their bloodstream, the initial question would spur a few from the crowd.

  • What sort of deck?
  • Does it matter how it’s structured?
  • Should I optimize for [time|space|clarity]?

I’m happy to answer–52 cards are fine, dev’s choice, and clarity, yes–always–but performance can come later. Five minutes of furious scribbling ensue before it’s pencils down and we check to see how everyone did.

Thumbs up if you’re feeling pretty good about your answer; thumbs down, if it’s eh, maybe not so good?

A few thumbs go up, many waver in the middle, and still more go straight down. The tyranny of averages, but call it “not good.”

And why not?

  • You put us under pressure.
  • You didn’t tell us what you wanted.
  • You didn’t give us enough time.

That’s exactly it! I’ve just done my best to make everyone feel like Will Smith. No introduction. No guidance. Not even the foggiest idea of why the test, or what it’s trying to achieve. I’m sure there are worse ways to do it. I’m not sure what they are.

The card-shuffling exercise is uncomfortable, high-pressure, vague, and–from the interviewer’s perspective–operationally useless. A deck-shuffling program (while convenient for a short workshop) has little to no utility on its own. We’re live-programming for the process, remember, and a cold test in isolated silence won’t tell us anything about it.

We spend the next few minutes talking about the hiring arc–what the stages are, who’s involved, what to expect, how to prepare, and so on–before getting back to the cards.

See, even if whiteboards are out of vogue, many teams still expect to see technical candidates program. Portfolios are great tools for representing overall ability, but they’re not as good at conveying process or the approach a candidate brings to new, less-familiar problems. Call it live-coding, pairing, or a take-home exercise. No matter the name–and no matter how others feel about it–the reality is that programming exercises maintain a significant presence in tech companies’ hiring processes.

So we take a second look at the cards.

Take Two

This time, we’ll focus on fixing the issues that were raised after our abortive first attempt. There’s more than one way to do this, but I’m particularly fond of a framework I stole from TDD. It should look pretty familiar:

  1. Write the spec – clarify problem and assumptions

  2. Propose a naive solution – discuss approach, revising assumptions as needed

  3. Implement it – take the spec’s ‘givens’ as input and return the expected value

  4. Validate – run the function (interpret yourself, if you have to) against the spec and fix any errors

Red, green, and–we’ll get to refactoring. But that’s the outline, and we spend the next part of the workshop doing just that.

1. Write the spec

It seems silly for something so simple as a deck of cards, but a spec ensures that our view of the world matches what the interviewer wants to see.

  • given: a deck of 52 cards
  • expect: the same deck with a different order

There are some assumptions, too, which we’ll also enumerate:

  • we can define our own data-structure (an array [0..51])
  • we can safely overlook the slim chance of a deck being shuffled back to its starting order

2. Propose a naive solution

Take a moment to think. If a first-pass solution isn’t forthcoming, it may be worth revisiting assumptions to try and simplify the problem. Once you’re ready with a naive answer, though, start talking through it:

I could shuffle by taking random cards out of the input deck and pushing them to the end of an output deck.

Fair enough! We can leave potential improvements for later; first, let’s get things working.

3. Implement it

Wrapping the spec up as a function will make it painfully clear what we’re out to solve, so let’s do that:

function shuffleCards (deck = []) {
  var newDeck = [];

  // leave space for the solution!

  return newDeck;

We have our input, our output, and plenty of room to act out the naive solution. Let’s add it:

function shuffleCards (deck = []) {
  var newDeck = [];
  while (deck.length > 0) {

  return newDeck;

We haven’t defined what spliceRandom is up to, but depending whether the interviewer wants to see it, we may get away with an obvious name and the assumption that it will do what it claims to do. The shuffling itself is implemented–we just need to make sure that it works.

4. Validate against the spec

Stepping through the implementation and comparing its behavior to the spec can help catch bugs or syntax errors. This is what interpreters are made for, but even on a whiteboard we can still interpret the code by hand. For instance,

function shuffleCards (deck = [1, 2, 3]) {  // [1, 2, 3]
  var newDeck = [];                         // []
  while (deck.length > 0) {                 // 3 > 0
    newDeck.push(spliceRandom(deck));       // [2]; deck == [1, 3]
  return newDeck;

If anything failed, we would fix it and try again. But this looks pretty good: iterating through the loop twice more, we’ll see deck gradually empty and newDeck fill up with randomly-ordered cards. Given a deck (check) expect the same deck with a different order (check).

5. Next steps

We have a naive solution, but it’s likely not the only answer. Next, we could optimize the solution in time and space; we could discuss concepts like functional programming or design considerations around mutable data; or we could even dive into more complicated use-cases or data-structures.

There’s always more to talk about.

Wrapping up

The second pass is always more fun than the first. Workshop participants throw out ideas, challenge assumptions, validate solutions, and engage much more like they would within a real team. And that’s really the goal–not to challenge technical ability, but to ferret out what working together is really like. How do you approach new problems? What challenges are you able to recognize preemptively, and what challenges are you able to overcome later? It’s not technical ability–your portfolio can speak to that–it’s your thinking, approach, attitude, and communication.

So have a conversation! Whether it’s a whiteboard, a pairing session, or a take home, talk through, think through, and communicate your process. The answer’s worth something, of course, but the Internet is full of answers: far more interesting is how you get there.