On developer interview questions

Recently I happened to answer a reporter’s question – “what is your favorite API interview question?” … Right, many of us have passed through multiple interviews on either side and have our own ‘favorites’ and ‘outsiders’. Many, who conducted interviews, have their list of questions or topics they want to have covered during an interview. Well, I have a few such lists.

But let’s turn the flow slightly from ‘what we want to ask’ or ‘what answers we want to get’ to ‘what result we want to achieve’. And the result is, quite frankly, that we want to hire a good candidate as fast as possible. Those invited as interviewees are our potential good candidates, we just need to confirm they are really good. So, this becomes the goal of the interview – confirm that the candidate is good.

All right, now we have a very practical goal, let’s explore the best way to arrive at it, shall we? Well, I think we should add one more dimension to our task. I think, many realize that an interview is never about one side asking and the other side answering – a good interview flows in both directions, and the interviewer is always an interviewee too. A good candidate is interviewing their interviewer – they need to be sure they want to work for this company/project/team. We should view every question we ask as an answer an interviewee receives and adds to their estimation.

Then our goal changes again: build up a dialogue in a way that the interviewer can explore the candidate’s skills and knowledge and at the same time to give the candidate a taste of what it is like to work for this project and team.

One of the ways I have tried successfully over quite a few interviews is to offer a small task and walk through it together. For example, such a question: please provide a contract for a service that will download a file from an HTTP resource.

Please note that we do not ask to create a working implementation of such a service – after all, an interview is time limited, and we have 10-20 minutes only for the task. It is enough to see a proposed contract – method signature, parameters, result type – and then develop the discussion forward. If the candidate provides a good design upfront and can justify it – great, our chances for success increase, and we can move forward to another question.

However, let’s take this task and a few imaginary solutions. Well, to be frank, not purely imaginary. For example, our candidate provides a very naïve suggestion, something like this:

byte[] DownloadFile(string url);
// or
Task<byte[]> DownloadFileAsync(string url);
// or
Task<byte[]> DownloadFileAsync(string url, CancellationToken ct);

So, how we could proceed from here? After all, the candidate may be a rather junior developer, and such code would be ok for a junior. Nonetheless, we could ask:

How would you implement it in a non-blocking way? Or what about being able to cancel an operation?

How would you ensure passing a valid resource URL?

What would be the result for various errors, such as ‘not found’, ‘connection aborted’, etc.? Would you throw exceptions or return a specific error result?

When the candidate answers these questions, they give many insights into their professional skills.

Then we could go further, for example, ‘how would you suggest implementing downloading large data over a potentially unstable connection?’ Let’s say, we have this suggestion:

Task<byte[]> DownloadFilePartAsync(Uri url, int blockSize, int blockIndex, CancellationToken ct);

We can then make one step further and ask about timeouts and retries, and about managing memory allocations in a constrained environment. At the end we may arrive to something like this:

Task<int> DownloadFilePartAsync(Uri url, byte[] buffer, int blockIndex, CancellationToken ct);

Is this contract good? As usual, it depends on a real-life scenario, but our scenario was to develop an understanding of our candidate’s skills. This task is very synthetic, as all such tasks in general are, but if we guide our discussion properly, we could understand quite a few things about the candidate skills:

  • API design and naming convention,
  • Asynchronous vs synchronous operations,
  • Cancellations,
  • Error handling and exceptions,
  • Knowledge of HTTP specific libraries and practices, such as Polly and retry policies,
  • Experience of working in constrained environments,
  • Memory management.

We can always dive deeper into any aspect during this discussion. Such as, ‘why would you avoid creating a new byte array in each call and reuse memory instead?’ Garbage collector, memory pools, byte arrays vs spans, etc. come into light.

We also have a good glimpse at very important soft skills:

  • How well the candidate can express himself,
  • How well the candidate responds to questions and comments typical for code review situations,
  • How creatively the candidate approaches the task.

Going through this task can take from 2-3 to 10-15 minutes. If we would ask direct questions about all these technical topics we would spend more or less the same time. And it is also more fun to solve a task :)

Well, and what about a candidate interviewing the interviewer? If we work with a task like this, and our discussion develops, the candidate gets the feel of that it is like working in this team. One of my main questions to my interviewers had always been exactly this – what is it like to work here? Alas, this question is very hard to answer, though an interview with a few such tasks would do that to an extent. An interviewer should always remember that a candidate is also estimating the position during the interview, and the interviewer is the main source for estimations.

Prepare 2-3 tasks to cover the most important aspects for your project/company, and after spending 30-40 minutes you will get a very good idea how well the candidate fits the position. Of course, regular ‘technical interview questions’ are also needed, as not everything can be covered by these tasks.

However, all these regular ‘technical interview questions’ and ‘algorithm interview questions’ have one peculiar quality: the candidates prepare for them. They find all these ‘top N interview questions for a XYZ developer’ and learn the correct answers. They go to LeetCode and learn to solve ‘algorithm questions’. There are multiple trainings and courses ‘how to pass an interview and get the job’ that make a candidate professional at passing interviews. So, then it is a question for an interviewer: your ‘good candidate’ is a professional developer or a professional ‘interview solver’? Let me say, they are not always the same…

So, do we not need all these ‘typical’ questions or algorithm-solving challenges? Again, it depends on a real-life scenario. There are positions that require mastering algorithms, there are positions that require more mundane coding skills. Any type of question asked properly can be useful when we listen with attention and develop the conversation further. Just remember the interview goal: hire a really good candidate; and that this goal splits in two – evaluate the candidate and convince the candidate.

Comments

Popular posts from this blog

Introduction, and welcome!

On AsyncLazy in .NET

On Serilog 'log enrichment' feature