This is part 2 of a series of articles themed “Preparing for Software Engineer Interviews”. My goal with the series is to document the steps I took while preparing for interviews for a software engineering position after working six years in predominantly support-leaning roles. I won’t break new ground here but rather share personal experience – anything you see here is an echo of what you can find elsewhere on the Internet. But too much of a good thing could be bad. Too much advice obscures itself and makes it hard to navigate. In part 1 I explained how I improved my knowledge of algorithms and data-structures as well as introduced a regular coding exercise. In this part I will explain how I went about improving interview coding skills.
When I was originally confronted with preparing for interviews I pulled many online resources together: posts on quora and stackoverflow, blog posts, articles and forum discussions. Some of the posts were quite detailed and comprehensive. There is lot of common advice but I struggled because there was just too much to do and too many ways to go about it. I decided to follow a simple plan which I will shortly explain below.
What is so special about software engineer interviews? The basic premise of most coding interviews (we’re talking about interviews at mostly large tech companies here) is to present a candidate with a novel problem that he has never seen before to see how good his reasoning and problem solving skills are. Presumably, a coding interview is a good indicator of candidate’s abilities and real-world productivity. Seeing how the candidate struggles under pressure, comes up with brilliant solutions and communicates with the interviewer is a telltale sign of his future success at the company. Unfortunately, that’s only a presumption and the reality is complicated but at the moment most tech companies stick to the same format which means that candidates must eventually go through it. So let’s look through some preparation ideas and shed some bullshit along the way.
First, there’s the novelty issue. It is not feasible to come with a completely new coding problem for every interview. Instead, inteviewers usually rely on a limited repertoire of problems. These problems eventually leak out and get shared online. More importantly, though, many problems share similar problem-solving strategies. Once the insight is known to a candidate the problem reduces to relatively painless translation to code. I’ve seen judgements against candidates that try to memorize solutions. But how can a solution be memorized? There are not 10 or 20 problems out there. There are hundreds, even thousands. Nobody would try to memorize the solution code line by line. But it is fair to assume that candidates memorize ideas and patterns behind the problems. How else could the candidates do well on interviews? Let’s take mathematics. Undeniably there is lots of memorization involved when learning any subject in mathematics. We can’t assume that candidates come up with algebra concepts from scratch during their short stay. Why then would it be fair to expect candidates to come up with algorithms that took very distinguished and persistent computer scientists and engineers to come up with?
In short, obtaining the insight and patterns behind coding problems and memorizing the right things is in my opinion the essence of interview preparation. Even the most distinguished engineers admit that in their day to day work they rarely get a chance to tackle difficult algorithmic challenges. I’m not saying that advanced skills are unnecessary and everyone should be an API coding monkey. I’m saying that candidates must work through typical coding problems, extract vital problem solving patterns and approaches. The fact remains, though, that some amount of memorizing is unavoidable. If a candidate didn’t have a need to optimize things at a very low level it’s unlikely he’ll come up with a good solution for bit twiddling questions even though he understands the underlying concepts well. He just wouldn’t have enough time. And certain efficient solutions are very clever to the point of being obscure and unintuitive. There’s little chance of coming up with one during 45 stressful minutes.
In fact, I would go as far as to say that some solutions must be memorized almost to the point of line by line. Okay, maybe not that far. But there are a some smaller-sized questions that interviewers like to ask as a warm-up. For example, to implement a power function or the greatest common divisor function. The thing is, interviewers expect flawless and, most importantly, quick (read immediate) implementation. Even if a candidate understands the idea it might take too long to translate that idea into code on the board. Plus, there are many possibilities for subtle common bugs, such as off-by-one errors, out-of-bounds, etc. Normally, a programmer is not rushed so there’s sufficient time to think, sketch pseudocode, implement and take care of edge cases. Because the problem is not difficult the interviewer will pick apart even the smallest mistakes and attach disproportionate weight to them. Clearly, candidates that prepared well will look more capable although it is debatable if their performance difference would translate in anything measurable in the real world.
Once a candidate gets exposed to a sufficient amount of problems (in the range of hundreds) there comes a plateau point. That’s completely normal and expected. Despite the acquired experience many problems won’t seem any easier. That’s also normal. In fact, this discourages many aspiring competitive programmers from further pursuing the challenge. Certain kinds of problems do not fall under neat patterns and require a different mindset. I personally haven’t yet managed to overcome this plateau. The good news is that such problems are rarely, if ever, asked in interviews. The bad news is that getting good at difficult problems worsens performance at interview problems. And the reason is that one tries to apply unconvential and complex data-structures and algorithms whereas most interview coding problems are centered around a set of relatively simple tools. Dead-ends are time consuming and reduce chances of solving the problem. After going through many rounds of mock interviews (which I discuss in the 3rd part of the series) I realized that I must recalibrate my toolkit and stick to simplest tools unless everything else fails. When my first thought reaches for a suffix tree I resist and instead try one of the following (not exhaustive): sorting, using a queue/stack, traversing, reversing, doing binary search, recursing. I also find it helpful to think of a brute force solution first. The lesson is that most coding problems are simple and rarely involve anything exotic. When they do the interviewer is prepared to almost immediately spill the beans on the magic insight.
So how to go about actually preparing? I have taken a whole month of full-time effort to specifically practice interview coding problems. There are many popular sources with coding problems, to name a few:
TopCoder – not suited well for interview preparation because of the nature of the problems, weird problem classification and an arcane UI. TopCoder is really a tool for competitive programming and it’s not designed for practicing interview problems. Given time constraints and different goals in mind I wouldn’t spend time on TopCoder.
UVA judge – automated system for submitting solutions to various competitive programming problems. Suffers from similar problems as TopCoder. Also, just like with TopCoder, it is hard to keep track of progress or to cover all topics.
Cracking the Coding Interview book – extremely popular book with around 150 coding problems and solutions. I went through an earlier edition years ago. Haven’t seen or used the recent one.
interviewbit – a well designed system specifically for preparing for interviews. Problems are classified by topics. There’s search functionality that lets, for example, to search for problems asked at certain companies. interviewbit also has an excellent gamified progress tracking functionality. Unfortunately, I found out too late about it. Otherwise, I would have likely used it as a primary preparation tool.
Elements of Programming Interviews in Java (EPI) book – this is my choice! The books comes with hundreds of problems with clear explanations of brute-force and optimal solutions. C++ edition is also available.
HackerRank – feels like a system which serves both competitive programming and interview preparation well. There are many practice problems classified by topics and regular hosted competitions. I have used HackerRank as a complementary resource.
GeeksForGeeks – a daily blog of coding problems. I have yet to come across an interview coding problem that is not published there.
Once I settled on a primary source I’ve done two passes:
Go through every problem in the EPI book and solve them algorithmically without writing any code. I’ve set a time limit of 10-15 minutes per problem. Once the time limit expired I consulted the solution. I think it’s better to have a time limit rather than get stuck for hours on a problem. Generally, I think it’s great to sometimes persist on a problem until it cracks but given the goals of interview preparation it’s more effective to absorb as many concepts as possible. For every problem I wrote down the main insight. It took me about 2 weeks to finish the whole book.
Go through every solved problem and write code for it. This is where I realized that my previously-written notes were terrible so I often had to solve the problems again. I wrote code on paper and I felt that writing code with the insight in hand is easy. I’m sure there are folks for whom finding the insight is easier.
I complemented EPI with problems from the HackerRank site. Finally, during two weeks leading to interviews I also solved every problem marked with the company I was applying for on interviewbit. You’d be surprised just how often widely publicized problems are still actively asked in interviews so it pays to go through them. I haven’t actually used interviewbit as a platform. Instead, I just read the problem descriptions and solved them on paper. Whenever I got stuck I consulted the hints or complete editorials (solutions).
After putting so much effort in the preparation can I say it was worth it? Did it help to get an offer? Getting good at solving coding interview problems takes a considerable effort and it is not a sure guarantee of success. However, a lack of such preparation is a sure guarantee of failure. There are too many factors vying for the final hire/no hire decision and success is anything but guaranteed. Just like with the algorithm and data-structure study I feel this effort made me a little bit better as a programmer. And just like with algorithm katas I would like to adopt a habit of regularly solving coding problems to improve further.
In the concluding part 3 I will talk about the final interview preparation steps and also talk about the psychological challenges that many candidates such as myself face before and during the interviews and the ways to tackle them.