This is the third post in the recruiting series that I’m currently writing! I’ve written two other posts, about my recruiting goals, and sourcing companies. In this one, I’ll be laying out the structure of the 3 different types of technical interviews I encountered, what studying techniques worked best for me to prepare for each type, and what my candidate experience was like for each of them.
I’d like to start by sharing that I’m not naturally gifted at technical interviews; they’re a far cry from what day to day work looked like for me. Last time I recruited, I underestimated how nerve-wracking and unfamiliar live coding would feel, and blew interviews with companies I was really interested in because of it. Even this time, I was rusty and stumbled over random things I’d forgotten about in my first few interviews, but over time, my pass rate increased, and my interviewing anxiety decreased. The best way I got better at interviewing, was by doing more interviews.
The goal of technical interviewing is to detect signals that the candidate would be a good fit for the role. I like to think that interviewers really want candidates to pass their interviews so they can spend less time interviewing and bring on more people to share their workload. But this needs to square with the risk that interviewers have of bringing on a teammate that ends up creating more hurdles than they help the team clear. As a candidate, everything I did in technical interviews was with the goal of giving my interviewer confidence that I’d be an asset to the team, and I kept in mind the general rubric that I used when I was an interviewer:
- Did the candidate solve the problem?
- Was their solution efficient and clean? Did they consider edge cases?
- How well did the candidate communicate their thought process?
- Were there any red flags during the interview?
The 3 types of technical interviews I encountered were: general data structure and algorithms (roughly 60% of my technical screens), building something practical (roughly 30%), and take home projects (roughly 10%). The structure of each is fairly different, so my prep varied accordingly. Before interviews, I asked recruiters the following questions to gain a better understanding of expectations before each technical screen, and what type of interview I’d be doing:
- What interviewing tools will we be using? CodeSignal, CoderPad, and CodePen are examples of shared coding environments I’ve used. It was helpful to play around with new tools to familiarize myself with how to navigate them and how packages like React or lodash were compiled.
- Should I have my own dev environment set up with some boilerplate? If yes, is it okay to install and make use packages such as lodash or jest?
- What am I being assessed on? Most recruiters would tell me what I needed to emphasize.
Data Structures & Algorithms
Prepping for data structure and algorithms was pretty straightforward – I use two resources: Interviewing Cake (paid subscription was 100% worth the value) and Leetcode. I did about ~50 Leetcode questions, and focused mainly on classic data structures and common strategies: strings, arrays, hashmaps, trees, recursion, sliding window algorithms, matrices, dynamic programming, and graphs. I didn’t bother studying more esoteric stuff because I wanted to be efficient with my time, and, well, I told myself I probably wouldn’t want to work at a place that was going to haze me through interviewing.
My strategy for practicing Leetcode:
- Pick a topic and do problems on that topic until I feel comfortable doing a random medium level question. The more I did, the more I noticed patterns in the solutions.
- Give myself an hour to attempt the problem as if I am in a real interview (e.g. talking out loud and verbalizing my thought process) before looking at the solution.
- Make sure I really understand the mechanics of the solution, rather than simply memorizing it. This helps me recognize how to adapt an approach for a slightly different problem.
- Schedule mock interviews with friends or via tools such as Pramp to mimic live coding pressure.
My strategy for actually doing the technical interview is pretty much ripped off of Amy Nguyen’s technical interviewing blog post, so I won’t repeat it here. I think the most important thing I had to remember in interviews was to avoid diving into coding before I had a full and complete plan of what I was going to do.
Building interviews were definitely my favorite kind because they most closely resembled the type of work that I expected on the job, and was already doing at my day job. The exercise was usually something along the lines of building a small feature (for example, the UI for a basic calendar app, or APIs to support a chatroom app). The problem is usually presented vaguely (let’s build a calendar) to get a sense of how engineers take a vague requirement and turn it into real functionality. While there wasn’t as much new material to refresh myself on, I took a very structured approach when I did these types of interviews that mimics how I build bite-sized functionality in real life:
- Clarify the domain: What functionality do we want to support? How does the typical user interact with what I build? Since I tend to be forgetful in high-stress settings, so I wrote down all requirements down to make sure I covered them.
- Identify edge case: What error states could the user hit? How would we handle those in our application?
- Communicate my plan: I talked about my approach and how I planned to organize my logic (this usually involved writing more than one component for UI work or multiple endpoints for server side work) and validated that my interviewer thought my plan was okay. I talked about technical tradeoffs if I could think of more than one approach, and interviewers would usually guide me towards the preferable ones. This is also usually where interviewers would drop hints about other things they wanted to see, or stuff I didn’t need to cover.
- Code: I compiled my code and validated my logic through user interactions often. As someone who has also been on the interviewer side of this process, it’s very hard to help candidates debug errors if they’re not validating it often. As a bonus, it gave me confidence that I was making forward progress in the exercise, and I could catch errors early by testing my own code regularly.
- As I code, I called out what I would do differently in a real life scenario: placing a component in a different file, creating a new child component, writing tests for my code, etc. and would sometimes ask my interviewer if they’d like to see these things. The answer was always no, but I think this signaled that I do think about things like code organization.
It was helpful for me to watch other implementation interviews on YouTube so I could mimic some of the approaches around communication or explaining technical decisions. Ben Awad has a good one that was fairly representative of most of my frontend implementation interviews, and after I watched it, I had a better sense of what I could expect.
Take Home Interviews
Take home interviews usually involved building something over a longer period of time. Companies liked to say that they should only take 2-3 hours, but I spent at least 6 hours on them each time I received one of these. There are always ways to make code better, and when I’m not time-boxed, work expands to fill the available time I have.
As an interviewer, I thought these were a great idea: there’s no live coding pressure, I can use whatever resources I want, and there’s no time limit. I think take homes are designed with the intention of improving the candidate experience, but they miss the mark when it comes to providing a good candidate experience:
- Feedback was never provided on the submission, so it also didn’t help me improve at all as an engineer. At least in live coding scenarios, there’s some collaboration and back and forth with the interviewer and you can identify areas that you’d improve upon.
- There was no way to gauge collaboration with other engineers. In real life, engineers typically ask clarifying questions and think of different ways to approach a problem, along with accompanying tradeoffs. Removing collaboration or visibility into the candidate’s thought process means you miss out on the why of particular approaches, and the candidate has no way of explaining.
- There was a huge opportunity cost for me to be working on a project for 6 hours because I could have used this time to study for my other interviews!
I guess this is a copout section because I don’t have good prep advice here – even though I passed most of these interviews, I never got feedback on why I passed or failed, and it was really hard for me to know what I was doing well or could improve on. I’m probably going to continue my experience of dropping out of interviews that want me to spend my weekends on their projects.
General Thoughts on Technical Interviewing
- If I had a nagging sense that there was something I could have done way better in my interview, I would work on the problem after the interview, and email an updated solution to my interviewer or recruiter, explaining that I fully understood my updated code might not be factored into the debrief. This is one of those things that doesn’t always work, but as a candidate, I felt like I didn’t have a lot to lose with this approach. The worst that could happen is that it wasn’t taken into consideration, and the best is that it changes the outcome of a decision because the company has a better sense of what I’m actually capable of.
- Communication is really, really key in technical interviewing. I’ve passed interviews where I didn’t complete every part of the problem (and some interviews are intentionally designed as such) but was given feedback that my communication provided a strong enough signal to move ahead. Interviewers don’t know what candidates are thinking if they don’t explicitly communicate it, and I do think that interviewers tend to drop more hints to candidates who communicate that they could use them.
- I focused on making forward progress rather than worrying about a complete solve because it was a way for me to remain calm and focus on the piece in front of me that I had to solve. When I encountered something I don’t know, I methodically tried different ideas that hopefully bring me closer to a solution, such as mocking data, googling a method (if allowed), brute forcing, or even writing the logic in pseudocode.
- When I received decisions about my interview, I always responded and asked for feedback. Surprisingly, what seems different from interviewing a few years ago is that I felt like many companies were willing to give me feedback if I asked for it. There wasn’t a single company I asked who said they couldn’t or wouldn’t. I took notes on my interview performance and tried incorporating feedback to help with future interviews, and it was really helpful to hear what I did well and could improve on to compare against my own perception of how I did in the interview.
If you read this post, I’d love to know what you thought! Drop me a comment here or on Twitter @chrystalzou.