Concurrency in a Senior interview
Concurrency belongs to two rounds in our practice: the coding round, where correct-looking code loses data, and the deep technical round, where you are asked why. Both test reasoning about interleavings rather than knowledge of the API.
An axis of our Senior backend target.
The check comes with every pass, covers all 8 competencies of our Senior backend target, and takes about 16 minutes. It reports each one as Ready, Borderline or a Gap for this level. It never predicts a pass.
Patterns our questions are designed to test at Senior
These are the distinctions the questions on this axis are written to separate — our judgement from writing them and having them reviewed, not a measurement of candidates. We have run no study, so nothing here is a statistic and none of it is phrased as one.
- 1.
Reaching for a lock before deciding ownership
The first question is which goroutine owns the data. A mutex around shared state is one answer; arranging for it not to be shared is usually cheaper and always easier to reason about. Locks added without that question tend to multiply.
- 2.
Cancellation that stops at your own function
A context accepted and not propagated leaves work running after the caller has given up. It is one way goroutine leaks start, and our questions test whether cancellation reaches past the function that accepts the context.
- 3.
Unbounded concurrency
One goroutine per item is fine until the item count is controlled by a caller. The bound is a design decision, and the interesting half is what happens at it: block the producer, drop the work, or fail the request — three behaviours a caller will notice.
- 4.
Data races confused with race conditions
The race detector finds the first. The second survives every tool: check-then-act, read-modify-write, a lock released between the two halves. Correct under -race and wrong under load is the case worth being able to describe.
What a strong answer sounds like: A strong answer says which goroutine owns which piece of state before it says which primitive guards it.
How the check measures it
3 questions drawn on this axis alone — 2 medium and 1 hard for a Senior target, because the bar is the level. Hard counts for one and a half times a medium, which is what makes the verdict relative:
| Medium right | Hard right | Verdict |
|---|---|---|
| 2 of 2 | 1 of 1 | Ready |
| 1 of 2 | 1 of 1 | Ready |
| 2 of 2 | 0 of 1 | Borderline |
| 0 of 2 | 1 of 1 | Borderline |
| 1 of 2 | 0 of 1 | Gap |
| 0 of 2 | 0 of 1 | Gap |
Three questions is coarse and the report says so beside every verdict. It is enough to separate this axis from the others in your target, which is what the check is for — there is no total, no percentage and no single number anywhere in the report.
What there is to practise
Questions here most often also test go language & runtime, reliability & failure modes, debugging and incident reasoning and data modelling & storage. Few questions on this axis test it alone, which is why the check reports every competency separately rather than averaging them.
One of them, in full
A question from the free demo, not written for this page. A demo quiz opens with it; the answer, the explanation and the source come when you submit — no account needed.
Answer it on the demoOne axis is not the loop
This axis is one of 8 in our Senior backend target, and being strong here says nothing about the others. The check covers all of them in one sitting and reports each separately, so what comes back is a profile rather than a score.