The Go Interview

Lesson 1 of 5

What Go Interviews Probe

"You can know the name of a bird in all the languages of the world, but when you're finished, you'll know absolutely nothing whatever about the bird." — Richard P. Feynman, What Do You Care What Other People Think? (1988)

Seven Parts of this volume have been about the bird. This one is about the twenty minutes in which somebody tries to establish whether you know it.

The gap between the two is real and it is not about knowledge. Plenty of engineers who write good Go interview badly, because the interview is a different activity: you are reasoning under observation, at speed, about a problem you did not choose, while narrating. And plenty of people who interview well write mediocre Go, because they have learned the answers to the questions rather than the material the questions are drawn from.

This chapter is about what is actually being probed. Not the question — the question is nearly always one of about a dozen — but the thing the question is a proxy for. Once you can see the proxy, the preparation stops being memorisation and becomes something much smaller: understanding the handful of places where Go's behaviour is not what a newcomer would guess, and being able to explain why rather than that.

The big question

Why do Go interviews keep asking the same small set of questions — slice aliasing, nil interfaces, closure capture, deadlocks — when any candidate could memorise the answers in an afternoon?

Because the answer is not what is being scored. Every one of those questions has a surprising result, and the interviewer is watching how you get there: whether you reason from the mechanism (a slice is a pointer, a length and a capacity) or recall a fact (append sometimes shares). The first generalises to a question you have never seen; the second does not, and the follow-up is designed to find out which you have. The question is a probe for a model, and the model is the thing being hired. That is also why "I don't know, but here is how I would find out" is a genuinely strong answer, and why a correct answer with no reasoning is a weak one.

What the question is actually for

Start with the most-asked Go interview question in existence, and watch what it is doing.

Go — Try it Yourself
Loading editor…
Output
Click Run to execute the code.

The result surprises almost everyone the first time, and that is the point of the question. What the interviewer is listening for is which of two explanations you give.

The weak answer is "append sometimes modifies the original slice." True, unhelpful, and it does not predict the second case.

The strong answer is the mechanism: a slice is a three-word header — pointer, length, capacity — and a[1:3] copies that header while pointing at the same array, with capacity running to the end of the original. append writes in place when len < cap and allocates a new array when it does not. Everything else follows, including why c was untouched and why the explicit copy is independent.

The difference is not knowledge, it is level of description, and it is visible in about fifteen seconds. Someone reasoning from the header can answer the follow-up — "what if I appended twice?", "what does cap(b) tell you?", "how would you make this safe?" — without having seen it before. Someone reciting the fact cannot.

This is why the preparation that works is not a list of gotchas. It is being able to say what a slice, an interface, a channel and a map are, in one sentence each, and deriving the surprising behaviour from that.

Everyday analogy

A driving examiner does not care whether you can recite the speed limit. They watch the mirror check before you pull out, because a mirror check is evidence of a model — you believe other vehicles exist and might be there — and the model generalises to situations the test cannot cover.

Interview questions are mirror checks. "What does this print" is not a quiz about append; it is looking for whether you think of a slice as a header over an array. That is why answering correctly but flatly scores worse than reasoning aloud to the same answer, and why a confident wrong answer with visible reasoning often scores better than a right one with none — the examiner learned something in the first case and nothing in the second.

The five things every Go interview probes

Under the surface variety, the same five capabilities are being assessed, and they are worth naming so you can hear which one a question is aimed at.

Go — Try it Yourself
Loading editor…
Output
Click Run to execute the code.

The five, and what each is really testing:

Value semantics. Whether you know what copying means for each kind of type. Probed by slice aliasing, by passing a struct to a function, by ranging over a slice of structs and modifying the loop variable.

Comparability and identity. What == does for structs, interfaces, and pointers, and which types cannot be compared at all. Probed by map keys, by struct equality, by the nil-interface question.

Method sets and interface satisfaction. Why *T satisfies an interface that T does not. Probed by "why does this not compile", which is a better question than it looks because the compiler error is genuinely confusing the first time.

Concurrency reasoning. The differentiator, and the subject of the next chapter.

Error and API judgement. Not "how do you handle errors" but "what would you export here, and what does that commit you to" — Part III's material as a design conversation.

Map iteration randomness deserves a note because it is a favourite. Go randomises it deliberately, since the runtime's authors saw code depending on an order that was never promised. The interesting follow-up is not "did you know" but "why would a language do that", and the answer — remove the accidental dependency by making it impossible — is the same reasoning as select's random choice in Part IV. Recognising that they are the same decision is exactly the kind of connection an interview is trying to surface.

A little history

Go interviews have changed shape twice. In the early years, roughly 2012 to 2016, they were mostly "do you know Go at all" — the pool was small, and demonstrating familiarity with goroutines and channels was often enough. As the language spread into infrastructure, they became concurrency interviews: worker pools, fan-in, deadlock diagnosis, and a great deal of "what does this print".

The current shape is broader and, for a well-prepared candidate, easier. Go is now common enough that interviewers assume syntax and probe judgement: why did you choose a channel over a mutex, what does exporting this commit you to, how would you know this is slow. The rise of automated screens — micro1 and similar platforms — has pushed the mechanical part earlier, so a timed exercise filters syntax and the human round is where the reasoning is assessed.

What has not changed is the small set of surprising behaviours the questions are drawn from. Slice aliasing has been the most-asked Go interview question for a decade, and it is the same question now as in 2013 — because it is still the clearest single probe for whether somebody thinks in terms of the underlying representation or in terms of remembered rules.

Reasoning out loud

The hardest interview skill is not knowing the answer; it is producing your reasoning in a form somebody else can follow while you are still forming it.

Go — Try it Yourself
Loading editor…
Output
Click Run to execute the code.

That numbered list is the deliverable. Notice its shape: each step is a fact about the mechanism, and the conclusion is derived rather than recalled. An interviewer following it can stop you at step three and ask "what if it were a map instead?" — and you can answer, because you are reasoning rather than reciting.

Four habits make this work under pressure.

State your assumptions before you start. "I am assuming Tags has spare capacity — if not, the answer changes, and I will come back to that." This buys you credit for seeing the branch even if you take the wrong one.

Name the mechanism, not the outcome. "A slice is a header" beats "slices are weird about append", and it means the follow-up is answerable.

Say when you are unsure, and bound it. "I am confident about the copy; I am not certain whether append reallocates at exactly this capacity, and I would check with cap()." That is a strong answer, not a weak one — it is calibrated, which is a thing interviewers are explicitly assessing.

Ask for the constraint you are missing. "Is this called concurrently?" changes the answer to most Go questions, and asking shows you know that.

The engineer's notebook

Three things to prepare that are not lists of questions.

One-sentence definitions. A slice is a pointer, length and capacity over an array. An interface is a type pointer and a data pointer. A channel is a synchronisation point that carries a value. A map is a hash table with randomised iteration. Almost every surprising behaviour in Go derives from one of those four sentences, and being able to say them is worth more than any quiz.

A worked example you own. One piece of concurrent code you wrote, that you can describe end to end: what it does, why a channel and not a mutex, how it stops, what you got wrong first. Interviewers ask for this constantly and a specific answer separates you from a general one immediately.

Your version numbers. Loop variables changed in 1.22, defer got cheap in 1.14, generics arrived in 1.18, slog in 1.21. Saying "that changed in 1.22" signals that you track the language rather than a snapshot of it.

Concurrency is where candidates separate

Every Go interview reaches concurrency, and it is where the distribution of answers is widest — which is exactly why it is weighted heavily.

Go — Try it Yourself
Loading editor…
Output
Click Run to execute the code.

Those four points are the marking scheme, and each maps to a failure mode from Part IV. What separates a strong answer is going one level further than correctness:

Say what would go wrong, not just what is right. "If Add were inside the goroutine, Wait could observe zero and return while work was still starting" demonstrates the model.

Name the ordering caveat unprompted. Completion order is not guaranteed, so any assertion must be order-independent — which is a testing point as much as a concurrency one, and mentioning it connects two areas.

Know the version detail. Passing n as a parameter was required before Go 1.22 and is now a style choice, because loop variables became per-iteration. Saying that precisely is a strong signal; saying "you always have to pass it" is a weaker one that was true two years ago.

The other question in this family is deadlock, and it gets its own chapter. What is worth knowing here is that the interviewer is usually not testing whether you can spot it — they are testing whether you can diagnose out loud, which is a different skill and the subject of Chapter 3.

In the real world

The most common way a well-prepared candidate loses a Go interview is answering the question that was asked instead of the one that was meant. Asked "how would you make this concurrent", they add goroutines — and the interviewer was checking whether they would ask what the bottleneck is first. Asked "would you use a channel here", they explain channels — and the interviewer wanted to hear "a mutex, because this is one variable and no coordination".

The second most common is unbounded confidence. A candidate who gives a crisp wrong answer with no hedging is harder to work with than one who says "I think X, and I would verify by Y", because the second is calibrated and the first is not. Interviewers are, explicitly or not, imagining you in a code review and in an incident — and in both, an unhedged wrong answer is expensive.

The third is under-using what you have already built. Most candidates have written something concurrent, debugged something slow, or made an API decision they can defend. Bringing that up unprompted — "I hit this in a service I wrote; we used a bounded pool because the database had twenty connections" — moves the conversation from quiz to colleague, which is the shift that produces offers. It requires having a specific example rehearsed, which is why it is in the notebook above.

The questions behind the questions

Most Go interview questions are proxies. Recognising the proxy tells you what a complete answer contains.

Go — Try it Yourself
Loading editor…
Output
Click Run to execute the code.

Read down the strong column and the pattern is consistent: every strong answer names either a mechanism or a procedure. Not a rule, not a preference, not an idiom — a description of how the thing works, or a way of finding out. That is the single most transferable observation in this chapter, because it tells you what to do when you meet a question you have never seen: reach for the mechanism, or reach for the measurement, and say which you are doing.

It also explains why "I don't know" is not fatal. "I don't know how sync.Pool behaves across GC cycles, but I would write a small benchmark with -benchmem and check whether objects survive a forced collection" is a strong answer to a question you cannot answer, because it demonstrates the procedure. The failure mode is not ignorance; it is a confident guess with nothing behind it.

Common Mistakes

  1. Memorising answers instead of mechanisms. The follow-up question is designed to tell the difference, and it takes about fifteen seconds.

  2. Answering correctly but silently. The reasoning is what is being scored; a right answer with no visible path teaches the interviewer nothing.

  3. Not stating assumptions. "Assuming this is called concurrently" earns credit for seeing the branch even when you take the wrong one.

  4. Unhedged confidence. A crisp wrong answer is worse than a calibrated uncertain one, because the interviewer is imagining you in a code review.

  5. Answering the question asked rather than the one meant. "How would you make this concurrent" is often checking whether you ask what the bottleneck is first.

  6. Quoting rules that changed. Loop variables changed in 1.22, defer got cheap in 1.14. "You must always pass the loop variable" was true two years ago.

  7. Reciting idioms as justification. "Channels are more idiomatic" is not a reason. "This is one variable with no coordination, so a mutex" is.

  8. Never mentioning your own work. A specific example you can defend end to end moves the conversation from quiz to colleague.

  9. Optimising without measuring, out loud. Saying "I would use pointers and avoid defer" to a performance question signals folklore rather than method.

  10. Treating "I don't know" as a loss. With a procedure attached — a benchmark, a race detector run, a profile — it is a strong answer.

Interview Corner

Interview Corner — the same idea at three levels. Answer yours; recognise the one above it.
Junior
Given a := []int{1,2,3,4,5}; b := a[1:3]; b = append(b, 99) — what is a, and why?
Model answer — a becomes [1 2 3 99 5]. The reason is what a slice is: a three-word header holding a pointer to a backing array, a length, and a capacity. a[1:3] copies that header, so b has length 2 but its capacity runs to the end of a's array — cap(b) is 4, not 2. Because len(b) < cap(b), append has room and writes in place, into the array both slices point at, so it overwrites a[3]. If capacity had been exhausted, append would have allocated a new array and a would have been untouched — which is why the behaviour looks inconsistent until you know the rule. So whether two slices share after an append depends on capacity, which is why a function that appends to a slice argument should return the result, and why I would use append([]int(nil), a[1:3]...) if I needed b to be independent.
Mid
What are you actually assessing when you ask a candidate that slice question?
Model answer — Whether they reason from the representation or from a remembered rule, and the two are distinguishable within about fifteen seconds. "Append sometimes modifies the original" is true and does not predict the second case, where capacity is exhausted and the slices diverge. "A slice is a pointer, a length and a capacity; append writes in place while len is under cap" predicts both, and it survives the follow-ups — what does cap(b) tell you, what if I appended twice, how would you make this safe. So I am not scoring the answer, I am scoring the level of description, because the mechanism generalises to a question the candidate has not seen and the rule does not. The same probe appears in several disguises — passing a struct containing a slice to a function, ranging over a slice of structs and mutating the loop variable, a nil interface that is not nil — and they all have the same shape: a surprising result whose explanation is one sentence about the underlying representation. What I would want to hear alongside it is calibration: someone who says "I am confident about the copy, less sure whether it reallocates at exactly this capacity, and I would check with cap" is more useful to work with than someone who is crisply certain and wrong.
Senior
How would you structure a Go interview to predict on-the-job performance?
Model answer — I would weight it towards judgement under realistic constraints and away from recall, because recall is the thing that correlates worst. Concretely: one short mechanism probe — slice aliasing or a nil interface — not to score the answer but to hear the level of description, since reasoning from the representation predicts everything else. Then a concurrency exercise with a deliberate flaw, where the task is to find and explain it out loud, because diagnosing under uncertainty is the closest proxy I know for incident work. Then a design conversation about a small service where the interesting decisions are Go decisions — channel or mutex, what to export, where the context goes, how it shuts down — and I am listening for whether they ask what the bottleneck is before adding goroutines, and whether they can say what a choice commits them to. What I would deliberately avoid is trivia with a single fact as the answer, anything where knowing a standard library function name is the gate, and puzzles with an aha step, because all three select for preparation rather than practice. I would also let candidates say "I do not know, and here is how I would find out" and score it well, since a calibrated engineer with a method is more valuable than a confident one without — and in an incident that is not a soft preference, it is the difference between an hour and a day.
Company lens — how the same topic gets asked
micro1Timed screen: mechanism questions with immediate follow-ups, so recall alone does not survive.
GooglePrecision: derive the surprising behaviour from the representation, not from a remembered rule.
MetaReasoning aloud: narrate a diagnosis while forming it, with assumptions stated.
AmazonJudgement: defend a design choice by what it commits you to, not by what is idiomatic.

Hands-on

Hands-on

Four exercises on the mechanisms the questions are drawn from. Exercise 1 is the one to be able to do without thinking — predicting aliasing from capacity is the single most probed thing in Go interviews.

Go — Try it Yourself
Loading editor…
Output
Click Run to execute the code.

Summary

  • The question is a proxy for a model. Interviewers score the level of description, and the follow-up is designed to distinguish mechanism from recall.
  • Prepare four sentences, not a list of gotchas — what a slice, an interface, a channel and a map actually are. Most surprising behaviour derives from them.
  • Five capabilities are probed: value semantics, comparability, method sets, concurrency reasoning, and error/API judgement.
  • A slice is a pointer, a length and a capacity, which explains aliasing, append, and why sharing depends on capacity.
  • Reason out loud in numbered steps, each a fact about the mechanism, with the conclusion derived rather than recalled.
  • State assumptions, and bound your uncertainty. Calibration is explicitly assessed; a crisp wrong answer is worse than a hedged uncertain one.
  • Ask for the missing constraint. "Is this called concurrently?" changes the answer to most Go questions, and asking shows you know that.
  • Every strong answer names a mechanism or a procedure — how it works, or how you would find out.
  • Know your version numbers. Loop variables in 1.22, cheap defer in 1.14, generics in 1.18, slog in 1.21.
  • "I don't know, and here is how I would check" is a strong answer. The failure mode is a confident guess with nothing behind it.

This chapter covered what is being probed and how to answer in general. The next narrows to the area where the distribution of candidates is widest and the stakes are highest: concurrency at the whiteboard. Producing a correct worker pool without a compiler, reasoning about a channel diagram somebody has drawn, spotting the missing close, and explaining why the obvious fix deadlocks — under observation, with no ability to run anything.

Editorial reflection

Technical interviews deserve most of the criticism they receive, and the Go interview is an unusually defensible instance of a generally indefensible practice. The reason is that Go's surprising behaviours are genuinely load-bearing: slice aliasing causes real bugs, nil interfaces cause real outages, and unbounded goroutines take down real databases. A question about append is not a puzzle with a trick — it is a direct probe for whether somebody will write a subtle data-corruption bug next month.

Where it still fails is the same place every interview fails: it rewards recent practice at interviewing rather than recent practice at engineering. An excellent engineer who has not interviewed in six years will underperform a mediocre one who spent a fortnight on question lists, and everyone involved knows it. The industry's answer — take-home exercises, pair programming on real code — is better and expensive, which is why it remains a minority practice.

What I would say to anyone preparing is that the overlap between "things that make you interview well in Go" and "things that make you good at Go" is unusually large, larger than in most languages. Understanding that a slice is a header, that an interface is two words, that a channel is a synchronisation point, and that concurrency must be bounded — those are not interview facts. They are the difference between code that works and code that works until Tuesday. Preparing for the interview by learning the mechanisms is, in this specific case, indistinguishable from just getting better, which is about the most that can be said for any interview process.

Q&A · 0

Enrol to ask questions and join the discussion.

No questions yet — be the first to ask.