Thursday, March 15, 2012

Tips for code interviews

If you are a programmer, then you inevitably spend some time every few years doing a bunch of interviews for a programming job. You probably are going to have to do some code interviews as part of that, which means you'll be doing coding interviews many times throughout your career.  Allow me to help.

Since I previously wrote a post on why I prefer coding interviews, I thought I'd follow up with some tips for doing well at these things.  I suppose it can also double as a list of things to look out for if you do code interviews.

The problem is, coding interviews, done well, are a pretty accurate gauge on your ability to code.  If your coding is rusty, it's hard for that not to show up during an interview. Still, there's a few things you do to help your chances.

  • If you are given a choice in languages, choose the most high-level language you are relatively good at.  So if you code mostly in C++ and sometimes in Python, use Python.  The coding will be faster and easier. If you aren't a regular user of any high-level language, though, better stick with what you know.
  • Know your chosen language well.  Know the standard data structures - sets / hashtables / lists / arrays.  If it's C++ or Java, know how to use Generics.  Know the features of the latest version.  If you tell me you primarily program in Java, but haven't used any version over Java 1.4, I'll feel you just don't care very much about programming.  On the other hand, if you tell me about upcoming features in C++11, I'll be pretty impressed.
  • Know when to use each type of data structure.  In Java, if you don't care about ordering, and items shouldn't have duplicates, don't use a List. Use a Set.  I am supremely annoyed when candidates just use LinkedLists for everything.  In fact, using it for anything is usually a bad sign.  Make sure you understand why.
  • You don't have to necessarily complete the whole program in order.  Feel free to write the main structure of the code, then fill in the more complicated bits later.
  • Go back and refactor code if possible.  Don't leave your code in a messy state if you think you have time to fix it.
  • Test out your code on an example.  I can't stress enough how important this is.
  • Choose meaningful variable names.  Not just good practice stylistically, but you are less likely to trip yourself up.
  • If the algorithm you are coding could be done in several different ways, choose the easiest way to code up first.  Then if you have time you can change it or just explain to the interviewer how to improve it.  It's better to have complete suboptimal code than incomplete optimal code.
  • Make sure you can figure out the running time of simple programs.
  • When physically writing on a whiteboard, leave as much space as possible between consecutive lines.  You often will have to go back and insert things in between lines.  Having to erase or write somewhere else and have an arrow pointing to the insert point will make things look confusing, which is bad for your comprehension.
Now, if you feel you are rusty or just a bit slow at coding, these tips won't help you too much if you can't actually code up the problem in question in time.  What you can do, though, is train this skill by doing coding exercises.  There's a few sites that offer small coding exercises, such as CodeSprint or  Project Euler.  Do these as much as possible before your interviews.  Don't just wait until you are actually about to interview.  Start as soon as possible.  

If you have any other suggestions for doing well in coding interviews, please share in the comments!

Sunday, March 11, 2012

The code interview

I was halfway through the bad interview when I realized that my method of interviewing was fatally flawed.  The candidate I was interviewing just did not make the conceptual leap to come up a way to solve the problem, no matter how many hints I gave.  The problem, which I don't wish to reveal, wasn't a classic a-ha type puzzle type problem, like the three lightbulbs controlled with two switches, but it was a software engineering problem that required some insight.

What worried me was that some candidates got the answer to my question instantaneously.  Almost no thought needed.  Oh, so you want to accomplish X?  How about a scheme that does Y?  Other candidates needed to think about it for some time.  But this one didn't get it even after about 15 minutes.  Are the ones that get it instantaneously really so dramatically better?  I knew from experience that many who came up with the answer fast didn't do well on the next part of the question, or overall in the rest of their interviews.

As the interviewee continued to metaphorically bang his head on the wall of the question, I realized that this part of the question was meaningless. I couldn't say for sure that a great performance on it would indicate a great engineer, or a poor performance would indicate a poor engineer.  Worse, my candidate had to struggle without making progress for quite a while.  He wasn't feeling good about it.

I was ultimately wasting time.  15 minutes spent determining that the interviewee can't answer a specific issue is 15 minutes that only yields a small amount of information.  Either the interviewer realized the answer or not, so I really only got that binary signal.  

At that time I had another question in my repertoire, which was a simple coding exercise, significantly more complicated the FizzBuzz, but less complicated than writing merge sort.  Pretty much the exact opposite of this type of question.  Anyone that can write code could do it.  But it turned out that performance on it was still variable, which was good, and I never got the feeling that performance was random.  Also, I was able to get all sort of signals: how fast the candidate wrote their code, if they remembered details about their language, if they made mistakes, if they remembered to test their code, etc.

After this bad interview, I switched almost exclusively to this simple coding exercise.  After I made the switch, I never had a bad interview again.  Candidates always made progress on this question.  They almost always finished the implementation.  They may have had to think about some parts, but they always left thinking they did a reasonable job.  And I never had to sit through and puzzle out how to drop hints to solve some algorithmic problem that the candidate is just not grasping.

With everyone pretty much able to finish the question, I judge candidates on the following:
  • How quickly were they able to finish the code?  
  • How correct is the code? 
  • After writing the code, did they go through the code to test it against some sample data?
  • How familiar do they seem to be with the language they are writing in?
  • How elegant is the code?
  • Is the code efficient?
Additionally, I'd ask a algorithmic question or two after this, if we have time, to see how they can speed up the code.

Usually, the answers to these are pretty well correlated.  If you can code elegantly, then you can usually code quickly, which them means you will have time to test and correct the code.  At the end, I think I have a good judgement of how decent a coder the person is.  If the candidate is a good coder, I almost always recommend hiring.

If you are thinking of asking a coding question, here are my recommendations, based on an interview time of 45 minutes:
  • Make sure you can write the code from scratch in about 15 minutes.  That doesn't sound like a lot of time, but you already know how to solve it, presumably, or else you wouldn't be asking the question.  All candidates, good or bad, take longer than you may think to code something up.
  • Have follow up questions that are algorithmic in nature.  What is the running time of the code?  How you can make it faster?  Could you parallelize it?  This is all for when the coding is finished.  If the coding never finishes, don't ask these questions.
  • Insist on real code, not psuedocode.  Let the candidate choose the language they are most comfortable in.
  • If you don't have a good coding question, look at the last few bugs you fixed.  Could one of them be an algorithm that could be simplified and turned into a coding exercise?  The existence of a bug is proof that the algorithm isn't too simple.
Judging a candidate can't be done through coding questions alone.  Algorithmic and design questions are necessary too.  But I'd ask coding questions first, since they seem to offer the most solid and reliable feedback.