If you like this post, I’d love it if you checked out my upcoming browser performance and load testing product: Browserpath.
I have a number of friends who are “junior” developers. Recently, one of them was telling me about an interview exercise they were presented for a junior Ruby developer job. I want to tell you the story of what happened when myself and another friend of mine tried to solve this task. We deployed two senior developers on a Junior interview task, and the results will astound you. I have some almighty reckons in this area, and I’d like to share with you what I think.
The Problem
My friend was asked to implement a linked list in Java in 30 minutes. “Not a problem!” I hear you cry. That was my initial reaction too. Even for people without a CS degree, I think a linked list is a pretty approachable data structure.
While I’d hardly call it obvious, once you’ve been presented with the idea that it’s a list of nodes, each with a pointer to the next, your brain can begin to see how it would work. Insertion takes the previous and next node, and swaps some pointers around. Deletion involves moving a pointer along 1 node. Search involves following the pointers until you find the item you’re looking for. This is one of the first “not built in” data structures you learn if you’re taught C on a university CS program. Linked lists are so useful that in a barren standard library like C’s knowing how to code one up is essential for basically any further CS programming exercise.
This seems like a really good interview exercise for a Junior developer. There’s a little bit of algorithmic trickery involved, but it by no means requires a CS degree. This is also very nearly a real world programming exercise. You get to actually write code. You get to debug, and print, and run code. You aren’t going to get caught out trying to brain your way through writing code against the wall. It’s not whiteboarding.
I was confused as to why my friend was so perturbed by the interview. That’s when they explained the part that I was missing. In one sentence I went from elated at the simplicity of the exercise, to horrified at the daunting complexity. They said to me “The interviewer asked me to make it to conform to List<T>
”.
Welp.
I suspect you’ve got better things to do with your life than spend it studying the interfaces in the Java standard library. So let’s break down what List<T>
actually is. List<T>
is Java’s generic interface for anything that implements an ordered collection that can contain many of the same value. It’s a huge interface. It’s got literally everything that you could ever need for a positional list data type. It’s got 25 public methods. Two of those return further interfaces that have a combined total of 12 public methods. That’s a total of 37 public methods for which you have to build and test in an implementation. The <T>
part means that it’s a generic interface. It can take any type. This is a ridiculous task. To state it again, my friend was given 30 minutes.
So… is this problem actually tractable for someone with less than two years of industry experience? Short answer: no. Long answer: to determine exactly how unreasonable this is, I wanted to “do a science” (to those of you familiar with the scientific method, feel free to blow holes in the approach below, I certainly know I can). I could have simply done this task on my own. I’m a “senior” developer. I’ve been programming Java for literally more than half of my life. My familiarity with the tooling is rusty, but deep. The amount of time it takes just me should be a reasonable lower bound on the task.
That, however, isn’t quite enough. To really push it, we can do better. Pair programming is one of my favourite techniques to get stuff done faster. It forces you to explain what you’re doing in your head, and get help when you’re fatigued. So, I grabbed my good buddy Stephen Best and we got going on the problem. The first 20 minutes we discarded to tooling setup, getting a sketch of the problem, getting a test suite live and so on. We’ll assume that in an interview context, that’s provided for you.
We started pretty quickly. In the past, Stephen and I worked together for 6 months, spending maybe a third of that time pairing together. We have a TDD workflow which works well for us.
We started by having Eclipse autogenerate the complete interface skeleton for us. At that point, we were basically ready to start implementing. Unfortunately, we didn’t realise the mountain climb of a task that we’d accepted for ourselves.
The best way that I can describe the process is a Long Fucking Slog. One of the nice things about the List<T>
interface is that you can implement some methods on top of others. The nasty thing about the List<T>
interface is that it’s fucking huge. After about 6 hours we gave up. We were defeated. Not only could we not finish the implementation in 30 minutes. We couldn’t finish the implementation in one sitting.
We got to the listIterator()
method, which has to return a ListIterator<T>
object and declared “time to log off”. Java: just when you’re nearly done implementing one massive interface, another one appears out of nowhere.
We got all of the basic operations complete, most with good test coverage. I can point to subtleties of the implementation that are required by the List<T>
contract that Java’s type system isn’t powerful enough to express. These parts of the contract are left to the implementer to ensure they’ve fulfilled. An example of something we skipped is range checking access. With mine and Stephens implementation you can totally ask for an element at position -17 or length + 12 and you’ll get a null pointer exception, not a range error. We skipped them because they aren’t absolutely enforced and we didn’t have the time.
I can’t possibly imagine the feeling that would go through a “junior” developer’s head when presented with this task. This is a Ruby development job. Why the person is being asked to implement a deep, wide and complicated interface in Java is beyond me. Certainly, a lot of OO thinking can be ported from Java to Ruby. Maybe that’s the point of the interview exercise. The only reason myself and Stephen were able to undertake this task is a lot of my familiarity with building generic systems in Java. When you write lines like: private <A> A reduceNodes(A accumulator, NodeCallback<A, T> callback) {
Which involves a class type parameter, a method type parameter and an anonymous interface callback, you’ve clearly gone off the Java deep end. We built that as an abstraction to build the rest of the system in a fairly DRY way. I’m pretty sure even the interviewer would be very confused if you did that in the interview. Maybe Stephen and I couldn’t get junior Ruby developer jobs if we did this interview. Maybe that’s a red flag.
So let’s talk about what this represents a little, before we move on. This is a “thinking under pressure” interview. You’re giving someone a problem that they clearly can’t solve in the time allocated. To reiterate: I’m pretty sure nobody can implement a List<T>
linked list in 30 minutes. That’s really not fair. Immediately you’re randomly filtering for people who are good at a kind of thinking which most programmers don’t encounter every day. Worse than that, you’re going to knock a lot of people’s confidence. In the next section, we’ll explore a few reasons why I think that we do this to junior developers.
The Ivy League CS Shibboleth
So, if an interview exercise isn’t filtering for people who can complete it, what is it filtering for? Well, your reaction to an impossible problem isn’t a thing that can be objectively measured. Instead of setting a problem where an interviewer measures “did or did not complete” one is giving the interviewer room to make subjective decisions.
Humans are weird. We’re wired to build tribes. Tribes are, prehistorically, the groups of people that were nearest to us (in a geographical sense). This means they’re people which look like us and we like to filter for that as much as possible. Giving the interviewer room to make subjective decisions almost certainly means that they’ll end up picking the people who look most like them. This is one reason why a lot of companies lead by people with CS backgrounds like to do whiteboarding interviews. Whiteboarding interviews are very good at selecting people with CS degrees from good universities. Privilege begets privilege and all that.
There is a problem here. In the past few years we’ve seen a huge surge in non-CS (calling it non-traditional seems like a joke given the age of our industry) people entering the industry. This new wave of junior developers are largely coming from bootcamps. A bootcamp doesn’t teach you how to build a red-black tree, or how to implement a hash table in C. They don’t need to. Most of their developers aren’t going to end up in places where they need to do those things on a day to day basis. That’s fine. It’s a pretty rare day that I need to break out my CS degree when I’m working on a Rails app.
Whiteboarding interviews, mostly, are actually really shitty. I’ve done a number of them in my life. I’ve literally never gotten a callback from one. I’m a white-cis-man with a masters level CS degree. So, at least anecdotally, the “select for people like us” filter doesn’t seem to be working so good. I guess my core issue with whiteboarding interviews is that I see them as a massive disconnect from the actual job most people do.
I find this to be problematic because we’re effectively locking bootcamp graduates out of a lot of junior programming jobs because of this legacy assumption that people entering the industry have a CS degree. This hurts us in a number of ways, particularly in terms of diversity. To my observation, bootcamps contain a much better cross section of society than is represented in a lot of CS degrees. The fees are certainly smaller than a lot of “ivy league” universities in the US, and the equivalent here in the UK (sorry for my anglocentric world view international readers!). These lower fees help (but do not entirely) democratise access and somewhat level privilege.
I’ve heard that a number of bootcamps have specific sessions dedicated to teaching their junior developers to answer whiteboarding questions by rote. Manipulating pointers, working with data structures that you don’t need to understand to build a rails app, and so on. Entirely because without those courses, the CS students have such an unbelievable leg up in these arbitrarily structured interviews. I’ve met a lot of bootcamp graduates in my time. Many of them I’d willingly hire over every final year CS student I currently know.
So, bootcamp graduates:
- They’re a thing.
- They’re really really good.
- If you’re hiring for a junior Ruby developer, you’re way more likely to find someone at a bootcamp than a CS programme.
Your interview is as much about giving a good impression as it is about finding the right person. If you give them some impossible whiteboarding or programming task, they’re not going to feel good coming out of the interview. That pressure hangover will follow them if they decide to join you. That’s a bad way to start an employee employer relationship.
A Senior Developer Interview Story
I’d like to tell you about some experiences with “senior” developer interviews. Both my own and those of others. Observationally, the “whiteboarding” element is completely gone at the senior stage. Often, but not always, the “coding” stage of the interview is also gone. Most of these interviews take the form of some kind of technical discussion with the interviewer. I’ve typically found that there’s some assumption that you might be more skilful than the person interviewing you. As such, they’re willing to listen to all of your ideas, and ask a lot of respectful questions about why you’re doing a particular thing.
To me, this kind of interview is much better. Whiteboarding stresses me the hell out. I don’t think I’ve ever ended up in a job that started with a whiteboarding interview as a technical screen. As in, I do so poorly in whiteboarding interviews that I cannot pass them. I’ve heard my good friend Justin Searls echo that same sentiment. In spite of this, I’d like to think that most of the developers I’ve worked with would describe me as effective. If your interview is filtering quality people because they can’t do an arbitrary exercise you’ve set, it might be time to take a good hard look in the mirror and work out what’s going wrong.
A technical discussion makes a much better place to start an interview. One isn’t under pressure to perform. Instead, one gets the opportunity to talk, correct previous mistakes, listen, react, and, generally learn about the person. Communication is the most important thing we do as developers. All computer problems are people problems. Let’s interview like that’s the case. One walks out of a technical discussion usually feeling pretty good. Interviewees like to spout reckons. Interviewers like to hear and react to those reckons. We get to work out if we can work together based on how reasonable our reactions are, whether we’re willing to give ground where we’re wrong, and, generally demonstrate how we like to work.
The most important technical work is done in acts of communication these days anyway, and as such we should really be designing our interviews around that model.
Conclusion: Better junior Interviews
One of my other friends is currently doing a round of junior developer interviews and has been studying 101 level CS like crazy. It’s paying off. I think that shouldn’t be the case. They’ve Repeatedly demonstrated, over two years, the ability to write production code that faces tens of thousands of people. They shouldn’t have to “study up” to get a job at the equivalent level to the one they already have. They should be able to talk about their day-to-day, what they do and do not. They should discuss the things they’re learning, what the other developers on their team are like, and what kind of environments they’re comfortable working in.
Computer science is beautiful, intellectually interesting, and appreciable by anyone who does programming. Most people don’t use the majority of what they learned on their CS degree in their day-to-day programming jobs. That’s fine! It does, however, mean that we shouldn’t filter for people who have CS degrees in our interviews for those jobs.
Let’s not torture our junior developers by forcing them to do the programming equivalent of making high school students studying the Catcher in the Rye and the Scarlet Letter. Let’s talk to them like humans who are writing software. Let’s find out whether or not they’re open to learning, good at communicating, and people we’d like to work with every day.