CHRISDOESCODING
LATEST
POSTS
KB

How I Survived the Technical Interview Process (with Tips!)

Mar 03, 2020


Back in November 2019, I lost my job when Kettlebell Kitchen went out of business.

Last I heard, the prevailing stereotype is that software engineers are infinitely hireable and that for the most talented engineers, you could lose or leave your job on a Friday and walk into a new job that following Monday (if you wanted).

For me, it took three months and ten days.

Preparing for technical interviews is very challenging for a lot of reasons, many of which might happen in ways totally out of your control.

Technical interviews, at their best, reflect software engineering as a whole. And in general, software engineering is a pretty difficult profession. It's abstract. It's logic. It's writing for and thinking the way a computer or robot might think. There are many ways of doing the same "thing", each with their tradeoffs.

Technical interviews ask you to flex your technical skills and more. To be successful, you must listen to a complex prompt/question, understand it enough to turn it into a way that a computer might be able to solve, explain it to your interviewer clearly, discuss tradeoffs, and finally hand-write the commands on a dry erase whiteboard in a room where an engineer watches.

While you prepare for technical interviews, you might feel like the concepts you're spending so much energy learning is a waste of energy to learn. And to be fair, the skills you learn to get ready for technical interviews is often correlated, but do not have a 1-to-1 application of its concepts to your daily work.

On top of this, while you're preparing for interviews, you've got to take care of everything else that life throws at you. You've got to go to your day job, which might have its own ebbs and flows of demanding-ness. Or, you might have just lost your job and you're under pressure to find something new to put food on the table at home. Maybe you're mentally losing your grip on sanity or deeply unhappy working at a job you hate and you need to run away to the engineering industry, where your passion is found. And the whole way, for many people I know, imposter syndrome is rampant and comes out in force as you struggle through the concepts.

So why would anyone subject their free time, energy, and mental faculties staring at data structures, algorithms, and system designs and bumbling their way through mock interviews just to get skills they will likely not use?

The obvious answer is because technical interviews are just simply the way that many employers use to assess candidates during the recruiting process. You've just got to do it. In a large way, this is the price of entry for the industry.

Some employers will break the mold and instead challenge their candidates with take-home assignments and small projects. Despite this, if you're looking for a software engineering job, chances are that most of the places you talk to will be asking you to solve a technical question on a whiteboard. And if you avoid such employers, then you'll be avoiding out a large group of employers: many of which would and could be great places to work.

What is a technical interview anyway?

For any non-software engineers reading this, let me take a quick aside to explain what a technical interview is more deeply.

"Technical interview", as you might assume, is a bit of an umbrella term that can cover a few different kinds of interviews.

One kind of interview is called a "system design" interview. These kind of interviews have an extremely broad question prompt. For example, the prompt might be:

"Show me how you would design Twitter."

The interviewer might say these words out loud and then sit back, expecting you to figure out the rest with follow-up questions and allow you to control the discussion and show your chops.

By far, the most common kind of interview is that of a data structure/algorithm interview. In this kind of interview, you'll be given a prompt for a problem to solve, and then you will have to write a function on a whiteboard that solves that problem.

Here's an example usually considered one of the easier ones: FizzBuzz.

Write a program that plays the game FizzBuzz. At the beginning of the game, you are given a target number (positive integer) to count up to. You then count out loud, beginning from the number 1, all the way to the target number. Whenever you reach a number that is divisible by 3, you should say "Fizz". Whenever the number is divisible by 5, you should say "Buzz" instead. And if the number is divisible by 3 and 5, then you should say "FizzBuzz". Otherwise, you would just say the number as you count upward.

Here's an example implementation of what you'd write by hand on a whiteboard:

def fizzbuzz(n: int) -> None:
    for number in range(1, n + 1):  # count up to the target n
        statement = ""
        if number % 3 == 0:  # number is divisible by 3
            statement += "Fizz"
        if number % 5 == 0:  # number is divisible by 5
            statement += "Buzz"
        if not statement:  # number is neither divisible by 3 nor 5
            statement = str(number)

        print(statement)

So yeah, your interviewer will sit you down, shake your hand. They'll introduce themselves, maybe tell you a bit about what they do at the company. Eventually, they'll jump into the interview by reciting the question prompt like the one above. Finally, they'll sit back and start taking notes while you work through it.

If you show signs that you don't know how to solve it, they'll often give you hints. You're expected to talk through your thought process and what the code you're writing is doing (demonstrating how good you are at translating a complex coding task into plain English).

Your interviewer is looking for how well you construct and form your explanations, whether you needed a little or a lot of hints to solve the problem, and also the quality of the code you hand write on the whiteboard. The code is expected to run successfully if copied into a program.

As challenging as it is, it can be quite fun.


Here's a harder one, with the solution, in case you're curious for more.

A stream is a collection of data that you can read from one "entry" at a time. It's like a stack of post-it notes. You know what's on the top of the stack, you know if the stack is empty or not, and you can pull the top post-it note off if you want. In this analogy, you can't divide the entire stack, you can only take from the top.

You are given N streams of integers. It might be 1 stream, it might be tens of thousands of streams. Each stream can be extremely long or short (you don't know). Finally, all integers within a single stream is already sorted in ascending order.

Write a function that consumes all N streams and creates a single sorted collection of integers.

Solving this problem efficiently requires knowledge of a special data structure called a "heap" which I won't explain in detail here, but in quick terms, it is like a magical bag that you can put numbers in. Inside the bag it is dark and you cannot read all the numbers already placed into the bag. However, if you reach your hand into the bag and pull out a number, it magically will only ever allow you to pull out the smallest number in the entire bag, no matter how many numbers are in the bag.

Here's just one way to implement a solution.

def combine_streams(streams: List[Stream]) -> List[int]:
    heap = []

    for stream_id, stream in enumerate(streams):
        if not stream.is_empty():
            heappush(heap, (stream.pop(), stream_id))

    result = []
    while heap:
        number, stream_id = heappop(heap)
        result.append(number)
        if not streams[stream_id].is_empty():
            heappush(heap, (streams[stream_id].pop(), stream_id))

    return result

Preparing for the technical interviews

Since I was unemployed, I needed to get a new job, and preparing for these kinds of technical interviews was the way to go.

My goal was to become "hireable", meaning "can pass a technical interview" in as little time as possible. In order to do that, I needed to study smartly. Studying for a technical interview is not that much different from studying for an exam or standardized test. First you acquire study material, then you learn the material, and then you practice for the test itself.

The usual resource for software engineers or would-be software engineers is LeetCode.

LeetCode Problems

I basically stared at this for dozens of hours for over a month

In case you don't know what LeetCode is, it's a website that has hundreds of data structures and algorithms questions, submitted by question writers and people breaking their NDAs to reveal questions they were asked during interviews at some of the biggest tech companies.

It's basically a free practice playground to prepare for your tech interviews.

I kept a notebook that I wrote in daily (or mostly daily). I marked the top of every entry with the number of days that I've been unemployed. This notebook kept me honest - I'd write down the LeetCode problems that I attempted, whether I was able to solve it or not, and then took notes on any big-picture topic lessons that I could glean from solving it, from reading the Solution page, or from discussing with other people.

My Notebook

Pages out of my notebook. Please excuse the handwriting.

Down the street from my apartment is a beautiful coffee shop (it's got a lot of plants and sunlight) that serves decent coffee, fast WiFi, and plenty of power outlets. Many of the people who come here are college students, who like me just need a surface to hook in their laptops, put on a big pair of headphones, and get to studying. I did most, nearly all, of my studying in this place.

Coperaco

Pretty, isn't it?

Usually, I'd try to get up and get to the coffee shop by 7:00am or 8:00am, and I wouldn't normally leave until maybe 10:00pm. I did this basically every single day for at least the first month to month-and-a-half of my unemployment. Now, this sounds like a lot (and it is), but I'd of course take breaks to eat or browse Reddit for a while. It wasn't head-down in LeetCode for 14 hours a day. I'd also of course adjust my schedule according to whatever I needed to take care of personally, like laundry, cooking, cleaning, etc. My wife and I even moved to a new apartment in the midst of all of this!

Sometimes you win, sometimes you lose

I'd spend hours and hours studying that when I came home, the only thing on my mind was about coding. If I allowed my mind to wander, it felt irresponsible, because I wasn't doing everything I could be doing to ending my unemployment.

When I did have free time, I played videogames more for its ability to help me "escape" rather than pure enjoyment of them. It's funny to think about it now, but I focused heavily on earning Steam Achievements rather than the story, primarily due to the feeling of "winning" that it gave me.

At the cafe, I'd usually not have anyone to talk to the entire time. Sometimes my wife would join me if she was working remotely that day, but we'd just merely be sitting next to each other, headphones in, and tuned in to whatever we were doing.

Each LeetCode problem solved was a "win" and each LeetCode problem that required me to give up and look at the answers was a "loss". Sometimes I won more than I lost. Sometimes I lost more than I won.

In the field of psychology, there's a concept on "Loss Aversion" that says that the pain of loss is stronger than the joy of gains. The small "defeats" compound quickly for me. LeetCode explicitly categorizes its problems in "Easy", "Medium", and "Hard" levels. It was incredibly deflating "losing" at "Easy" problems, even if I had just finished solving numerous "Hard" problems moments before.

Some nights, I'd go home feeling totally defeated, staring at an actual, real interview I've got scheduled on my calendar, wondering if I'd ever be ready or good enough to pass.

To get through this, I stuck to my methodical approach to solving these questions, reminded myself about all the things I had learned since I started preparing, and remained hopeful that I could get through this job hunt intact and with my career still in an upward trajectory.

Solving a problem took these steps:

  1. Read the problem, understand the inputs and what you're expected to output.

  2. Think about what "family" of questions this question falls under.

  3. Think about what are the best data structures to use for the approach.

  4. Think about my actual approach to the problem.

  5. Determine whether there was a faster way to solve the problem (if so, go back to step 3).

  6. Hand-write the solution into a dry erase board or in my notebook.

  7. Re-read the solution I just wrote, see if it would compile and if it would actually solve the problem. Fix any bugs if so.

  8. Copy the solution, word for word, into the LeetCode editor.

Secondly, learning from the problem took these steps:

  1. On LeetCode, if the "Solution" tab is enabled, go ahead and read through the entire thing.

  2. On LeetCode, go to the "Discuss" tab of the problem and see if other people came up with better solutions.

  3. If I still don't understand the solution, luckily most questions have variants that can be found through Google or on YouTube with explanations. Seek those out too.

  4. If I correctly solved the problem with the most efficient solution, write this down in the notebook, along with the "family" that the problem falls under and the approach/thought process that got me there.

  5. If I correctly solved the problem with an inefficient solution OR if I was unable to solve it at all, re-do the problem with the new knowledge I have from the Solution and Discussion tabs. Write down the new knowledge in the notebook.

If I could give any recommendation on this point, it's to find like-minded people who are going through the interview hiring process at the same time that you are. If I had people to bitch to, complain to, bounce ideas off of, joke with, but most importantly understand the kind of experience I was going through, it would have helped lighten the load for me immensely.

Revel in the days you feel you "won" more than "lost". Count your blessings. If you solved a Hard problem that you would have never solved a week ago, then praise yourself for that achievement, even if that feels weird to do.

Also, if you can -- start working out at the gym, even if it's a little. It helps to find reasons to get out of the house, since it's really easy to get a little too comfortable in your sweatpants while in unemployment.

For me, I ended up solving 286 problems on LeetCode within my first month to month and a half of unemployment, roughly speaking.


Here's a breakdown of those 286 problems, in case you're curious.

  • Breakdown by Difficulty

    • 64 Easy

    • 151 Medium

    • 71 Hard

  • The following are included in the above counts:

    • All 85 problems in the "Get Well Prepared for the Google Interview" track

    • All 68 problems in the "Top Questions from Amazon" track

  • The "Rock the Behavioral Interview Question" track

Even more preparation

Technical interview preparation is not all LeetCode, however. LeetCode doesn't prepare you for system design interviews, mentioned previously. LeetCode doesn't prepare you for behavioral design interviews, either, and contrary to a widespread belief that software engineers don't need to be good at behavioral interview questions, you actually do (surprise!).

LeetCode also doesn't provide you with a real interviewing environment, where you've got 45 to 60 minutes or less to solve a problem, where you have to explain your solution to another living human being, and where you might be given hints along the way.

Furthermore, if you're a self-taught software engineer, like me, there might be some concepts/techniques needed to solve some LeetCode problems, but that you simply never learned. I knew I would need to teach myself these concepts, and I wouldn't easily find materials to do that on LeetCode.

To do this, I located a few key resources for information, even if it meant paying actual money for them.

The first was a YouTube channel run by a competitive programmer named William Fiset. This is just my opinion, but I think his channel puts the rest of the "learn data structures and algorithms" YouTubers to shame. His videos are incredibly concise and I learned so much just from watching his work. It's also free!

William Fiset's Channel

William Fiset's Channel

The second big one for me was Educative.io's "Grokking the..." courses. I paid and took three of them: "Grokking the System Design Interview", "Grokking the Coding Interview", and of course, "Grokking Dynamic Programming Patterns for Coding Interviews".

  1. Grokking the System Design Interview was useful for system design interviews. Without it, I wouldn't have gotten my job offer at Amazon. At my onsite I was asked to design a synchronization-focused architecture, and I relied heavily on the lessons I learned in this course.

  2. Grokking the Coding Interview was less useful overall to me since by the time I went through the course, I was doing pretty well at LeetCode problems and had a lot of the techniques it teaches in my back pocket. The benefit of this class was the fact that it put names to the techniques I had self-taught or discovered by solving dozens and dozens of LeetCode problems. Having names for these techniques allowed them to "fit" in my brain in a more organized way, and I could recall them much faster and with more clarity.

  3. Grokking the Dynamic Programming Patterns was incredibly useful. When an interviewer really wants to test a candidate, the arguably hardest "class" of technical interview questions involve dynamic programming, which is a programming technique for solving very complex problems. Dynamic Programming problems were such a huge gap in my understanding that paying for this class was well worth it to me. At my Google onsite, I was asked two dynamic programming problems from two different interviewers and I relied on the lessons and approach taught in this course to answer them.

Grokking the System Design Interview

Educative.io

The third big resource for me came pretty late in my job hunt and preparation, but was extremely useful: Amazon's 14 Leadership Principles. Why was this useful? Amazon is notorious for its interview process, which puts a huge emphasis on behavioral interview questions. It's split about 50/50 between time asking behavioral questions and time spent on technical coding problems. Their behavioral questions are geared towards their 14 leadership principles and they frame the questions in a way that allow you to either show or not show you you demonstrate any of the given principles.

Amazon's Leadership Principles

Amazon's Leadership Principles

In preparation for just the Amazon interview, I took the list of all 14 principles, and then below each principle, I wrote two stories in STAR format from my career that shows how I have that leadership principle. This was not easy. I had to do a lot of introspection, staring at my ceiling, searching for memories on the job with which I could construct a story.

Why was this useful? Amazon's leadership principles are not unique. If you take any decent company out there, you'll find that they overlap with multiple of these principles, which means that by constructing stories for these principles, you will, at the same time, prepare stories that you can access and use in interviews at other companies.

Final Thoughts

There's still so much more info to give on my experience. Finding potential employers was itself a challenge, as well as the interviews themselves. The biggest tech firms put you through full-day interviews that are exhausting to say the least.

This post is getting quite long as it is on its own, but before I go I've got a few summarizing points to make:

  1. Mental health and your morale is critical throughout this entire process, especially if you are either desperate to get a new job or are without a job at all (or both!). Count your blessings and revel in your wins. Don't let the pain of loss overpower the joy of gains.

  2. Your "team" of friends and family are critical as well. For me, my wife was absolutely instrumental. She didn't "get" the computer science-y stuff I came home to talk about, but she did "get" the challenge and why all of this was such an adventure. I couldn't have done it without her.

  3. Quality of interview resources beats the quantity of interview resources used. Try to get an understanding of what a resource can teach you before you commit your time to it. Your time is valuable! Don't embark on a months-long MOOC if you want to get a job soon.

  4. Find communities that can talk to you about data structures and algorithms. You'll learn about techniques and things that you never knew you needed to know.

  5. Do make good use of mock interview sites like Pramp and Interviewing.io. First, you get the chance to flex your interview skills and practice in front of a real person. Second, you actually meet a person who is likely in the industry or will soon be entering the industry! A handful of people I met gave me plenty of tips and the low-down of what it's like to work at some of these places. Others have explicitly offered to give me a referral to their company should I want it. These are great connections, don't squander it!

That's all for now!