Tag Archives: programming

3 Types of Technical Interviews

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:

  1. Did the candidate solve the problem?
  2. Was their solution efficient and clean? Did they consider edge cases?
  3. How well did the candidate communicate their thought process?
  4. 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 Functionality

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:

  1. 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.
  2. Identify edge case: What error states could the user hit? How would we handle those in our application?
  3. 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.
  4. 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.

Overcoming Imposter Syndrome: Symptoms and Cures From a 0.1x Engineer

It’s been just a little over two years since I decided to make a serious commitment to the journey of programming. I wanted to document as much as I remember of the first hard parts of that journey because I don’t want to forget how unfeasible the idea of becoming an engineer was at that point. Now that I am one, it feels like it takes more effort to remember the challenges of setting up my environment, learning git, and understanding why time-space complexity mattered, because these are things that I now work with day to day. I’m sure that, as I gain more programming experience, the idea of not understanding fundamental programming will become more and more foreign to me.

Why is it important for me to recall what that frustration felt like in the early days of my programming journey? For as long as I’ve started programming, I’ve always felt a sense of imposter syndrome. That’s not new, and as I began interacting with more people and reading more developer blogs, I came to realize that everyone experiences imposter syndrome to some extent, from CS PhD students, to distinguished architects who have spent decades in the software industry. For me, imposter syndrome felt like it prevented me from learning what I wanted to learn, and building what I wanted to build. It made me fearful of asking questions, because asking questions meant I didn’t know the answer, and had failed in my attempts at trying to find it. Sometimes, my imposter syndrome would consume an entire day of development. Instead of asking my question, I’d peruse forums and documentation, faulting myself for not knowing how to solve a seemingly trivial problem. I was constantly comparing myself to other engineers, impressed with just about everything they did, while minimizing my own accomplishments, and did not sleep through several nights, anxious of being found out that I, in fact, could not build anything worthy of shipping. In fact, when I won a hackathon for the “Most Shippable” feature category, I chalked it up to being on a team with 3 other incredible engineers, and still mostly believe that they contributed more than I did to that project. When my manager gave me my annual performance review, I was mentally prepared for a demotion, or to be let go; when I was given a raise in salary and equity, I felt stressed instead of excited, because I felt like I’d have to bullshit twice as hard to keep up a convincing image of myself as competent. Imposter syndrome is not a self-pitying experience. I deeply believed I was incompetent at programming because I was not intelligent enough. Such are the effects of an inaccurate and unfounded assumption that engineering is a discipline that operates as a pure meritocracy.

I’m not immune to imposter syndrome today, but compared to how much imposter syndrome used to affect me, it’s much more manageable. Documenting overwhelming experiences brings me back to a place where I can better empathize with people who do feel that way. Now that I know the answer to many of the issues I encountered at the start of my journey, I also catch myself slipping into a mindset of thinking certain tasks are simple, forgetting my own struggle to understand the fundamentals as recently as a few years ago. The most important thing I learned brought about significant shifts in the way I dealt with my own imposter syndrome:

Learning How to Ask Thoughtful Questions

This is the single most impactful thing I learned to do, that helped me feel more at ease with imposter syndrome and its effects on me. I was lucky to have a mentor who gave me a good set of guidelines to asking thoughtful questions to other engineers, that I still use to this day when I’ve failed to find an answer on my own:

  1. Peruse related documentation and parts of the codebase. This one seems obvious, but it’s embedded in the assumption that agreements and truths are also well-documented somewhere others can reference, and in language they can understand. A friend of mine once told me he believed that it’s the authoring engineer’s responsibility to make sure their code and docs are understandable. If they aren’t, you should feel totally okay seeking clarification about anything unclear or ambiguous. I give myself a 30-minute time limit to hunt through docs, code, and Google before asking any questions, just to make sure the obvious places have been searched.
  2. If the answer hasn’t been found, or is unclear, it’s time to ask clarifying questions. I ask my questions to a team Slack or specific channel for that tool / technology, because if I’m wondering about this, it’s likely others have, or will in the future. Asking questions in public forums, daunting as it may seem, benefits many people besides yourself. I almost always ask my questions in the form of: “I’m trying to accomplish x. I’ve looked at the README, the docs, and wiki page y. I expect output z, but I’m getting this error when run this series of commands instead”, followed by any relevant code snippets and error logging. The more detailed you can be, the better. As someone who has been the asker and answerer of questions now, I can confidently say that an answer is found much more quickly if more details are provided.

About 90% of the time, someone will respond with some thoughtful clarifying questions (e.g. what version of Postgres are you running?) and we figure out the issue. Sometimes, we identify it’s a bug, or that something was missing from the documentation. Either way, this approach demonstrates 3 things:

  1. You made an effort to solve the problem on your own first.
  2. You communicate about problems and the attempted solutions clearly.
  3. You share your findings about solutions with others who may be impacted.

Edit 5/14/20:

It’d be misleading and inaccurate to say that I made progress on coping with imposter syndrome by myself, but I wanted to emphasize learning how to ask thoughtful questions because it’s the one that most people can do without relying on factors outside of their control, which makes it the most empowering and beneficial. Here are two other factors that had major impact on my ability to overcome imposter syndrome:

A Psychologically Safe Culture

I hesitated about including this, because the word “psychological safety” has been thrown around so often in the tech industry that I feel like it’s turned into more of a buzzword than something people can actually understand, so I’ll do my best to start with my own definition of it. To me, psychological safety means feeling like I will not be rebuked in any way for being honest. In the context of asking questions, rebukes can take many implicit forms; anything from thinking of the asker as less competent, to outright patronization of their abilities in front of others. The reason psychological safety is important when it comes to imposter syndrome, is because the very definition of imposter syndrome includes psychological danger: a fear of being seen or treated as incompetent.

I got extremely lucky at work, and with my teammates. People say I totally drink the kool-aid for my team at work, but I’ve held enough jobs, in enough roles, to realize that the team I got to work on was anomalous in its emphasis on balance, culture, and openness. At the time, I was the only junior engineer on a team of senior and principal engineers, and each one of them demonstrated infinite encouragement and patience towards me when I couldn’t figure something out. Small reassurances like “Don’t worry, this is hard stuff!”, “I don’t know”, or “It happens,” when a particularly silly mistake was discovered (like the time I wondered why a commented-out variable was returning undefined, oops) added up over time and reminded me that no single engineer will have the answers to everything. So often, I tend to place those I admire on pedestals, and internalizing the fact that brilliant engineers are fallible humans also helped me trust in my own capabilities a little more.

It’s really unfortunate that this type of culture seems to be a rarity amongst engineering teams, and I have a lot to say about how lack of it also disproportionately affects underrepresented groups, who already struggle more with combating imposter syndrome’s effects. But the good thing is that, if you’re an engineer who is more senior, little gestures like the examples I mentioned above are simple ways to reinforce psychological safety within your team.

Mentors at Work

The last thing I’ll mention that was hugely beneficial for my programming confidence are my mentors. For as long as I can remember, major changes in my career have always been driven by the confidence a trusted mentor has given me, including deciding to become an engineer. I have 2 mentors at work, and if nothing else, my mentors provide me with a psychologically safe outlet to express concerns, run ideas by them, or ask for feedback in a focused way. Even though my manager and I have a great relationship at work, talking to someone who doesn’t influence my salary and career development can take away the pressure I feel with admitting shortcomings or fear. I run things I feel unsure about by my mentors, such as “What do you think of the way I worded this concern?”, to “Do you think my understanding of this problem is correct?”, to “Can you review this MR or this design document?”

Everyone’s relationship with their mentor is different, but I personally rely on mine to be my sounding boards and advisors when it comes to career development or learning a new skill. I don’t have recurring meetings with my mentors; the relationship is casual, and I message or meet with them when I have a specific topic in mind. It’s also important to remember that they, like everyone else, don’t have the answers to everything. One of my mentors shared with me that he experiences imposter syndrome at least 3 times a week! The dynamic I have with them is slightly more involved than I have with peers, in the sense that they embody skills or abilities I’d like to have in a few years. Getting their perspective on what they would do in a particular situation I’m facing helps provide me with a starting point.

Imposter syndrome is something I know I’ll never fully conquer, and if I’m totally honest, I’m not sure I want to. While it can feel discouraging at times, recognizing that I have room to grow holds myself accountable for making those improvements, and aspiring to higher standards for myself is the kind of mindset I want to embody now, and in the future. Realizing that I was fortunate to have resources at my disposal was great, but realizing that I can accomplish most of the work to turn it into a positive behavior reinforcement was even better.