Python, Go or Java: which backend interview are you actually in?

Three companies, three backend roles, the same CV. One asks how you'd keep a slow endpoint from blocking everything else, one asks what happens when two goroutines touch the same map, and one asks why your object stopped working as a map key. The job is the same. The interview isn't.

PracticeDepth team8 min read

Every language round goes looking for the same thing: whether you understand what your tools do when you're not watching. What changes is where the language hides that. Each of these three makes something effortless, and the interview goes straight to whatever the effortless thing costs.

Knowing which round you're in is worth more than another week of general preparation, because the three do not overlap nearly as much as their job descriptions suggest.

The one-line version

  • Python makes writing code fast, so the round asks what the runtime is doing underneath: concurrency choices, the data layer, and where the convenience costs you.
  • Go makes concurrency cheap, so the round asks whether you can keep it correct: shared state, cancellation, and what happens when a goroutine outlives the thing that started it.
  • Java makes big systems survivable, so the round asks whether you understand the machine and the framework underneath you: memory and garbage collection, collection contracts, and what your framework is doing behind an annotation.

The Python round: what is the runtime actually doing?

Python interviews assume you can write it. What they check is whether you know the cost of how easy it was.

  • Concurrency, always. Which of threads, asyncio, processes or a queue fits a given slow endpoint, and why the lock matters for one of them and not the others.
  • The data layer. The N+1 query is nearly a certainty, because the ORM makes it so easy to write without noticing.
  • Definition-time behaviour. Mutable default arguments, shared class attributes, anything created once at import and reused forever.

The trap is answering like a tutorial. "The GIL means threads don't help" is the answer everyone gives, and it's wrong often enough to cost you, since the lock is released around I/O. Python interview questions for backend engineers works through the six questions this round reaches for.

The Go round: is your concurrency correct?

Go's surface is small enough that nobody spends the round on syntax. They spend it on the two things Go makes easy to write and easy to get wrong: concurrency and errors.

results := map[string]int{}

for _, id := range ids {
    go func(id string) {
        results[id] = fetch(id)   // concurrent write to a shared map
    }(id)
}
The classic Go interview snippet: no compile error, a data race at runtime, and a crash that only shows up under load.

What's wrong with this, and how would you know?

Junior answer

The goroutines all write to the same map, so I'd add a mutex around the write to make it thread-safe. There's also no WaitGroup, so the function returns before they finish.

Senior answer

Both of those, and the reason it matters more than it looks: concurrent map writes aren't just a lost update, the runtime detects them and kills the process. So this is a crash under load, not a subtly wrong number. I'd either guard it with a mutex, or have each goroutine send to a channel and let one reader own the map, which I prefer because ownership is easier to reason about than a lock. And I'd run the tests under the race detector in CI, since that's what turns this from something you notice in production into something you notice on the branch.

The follow-up is usually about the loop variable. Older Go versions shared one variable across iterations, which is why the id is passed in as an argument here, and it's a good moment to say which behaviour you're assuming.

Expect these three as well, in almost every Go round:

  • Context. How cancellation propagates, what happens to an in-flight database call when the caller goes away, and why passing context down is not a style preference.
  • Errors as values. When you wrap, when you check with errors.Is or errors.As, and why the explicit return is a design choice rather than boilerplate to be tolerated.
  • The nil interface. A nil pointer stored in an interface makes the interface non-nil, which is the single most reliable Go gotcha there is, and the reason a function returning a concrete error type can break an == nil check at the caller.

The trap in a Go round is over-engineering. Reaching for channels when a mutex is clearer, or a goroutine pool when the work is already fast, reads as someone who learned the features rather than the judgement. Saying "this doesn't need to be concurrent" is frequently the senior answer.

The Java round: what's the machine and the framework doing?

Java rounds cover more ground than the other two, because there's more underneath you: a virtual machine you didn't configure and a framework doing work you didn't write.

Your service pauses for a second every few minutes. Where do you look?

Junior answer

Probably garbage collection. I'd increase the heap size so it doesn't run out of memory and collect so often.

Senior answer

GC is the first suspect, so I'd turn on GC logging and look at whether the pauses line up, and whether they're young or full collections. A bigger heap can make it worse, because a full collection then has more to walk. The usual cause is objects being promoted that shouldn't be: a cache holding everything, or request-scoped objects living longer than the request. If the pauses are real and the allocation rate is the problem, a low-pause collector is a real option, and so is allocating less. I'd also rule out the boring answers first, since a periodic stall can just as easily be a connection pool, a lock, or something synchronous on a scheduled job.

Naming the tool matters here: GC logs, a heap dump, and comparing two dumps rather than staring at one. Candidates who only say "more heap" are describing a setting, not a diagnosis.

  • equals and hashCode. The contract, and what breaks when you override one and not the other: an object lands in a hash bucket under one hash and is looked up under another, so a key you put in is genuinely not findable.
  • Concurrency. Executors over raw threads, what a thread pool does when its queue fills, and where virtual threads change the calculus for I/O-heavy work and where they don't.
  • The framework's magic. With Spring, what dependency injection is actually wiring, and what a transaction annotation does: a proxy wraps the bean, which is why calling an annotated method from inside the same class often means no transaction at all.
  • Streams and collections. Laziness, when a stream is worth it over a loop, and the difference between a list you can add to and one the API handed you.

The trap is answering with framework annotations instead of behaviour. "I'd add @Transactional" is a configuration. What gets scored is knowing what it wraps, when it silently does nothing, and what happens to it when an exception is thrown.

What every one of the three asks anyway

Underneath the language, these rounds converge, which is the good news if you're switching:

  1. What does this do under load? All three want to hear you name the component that gives out first.
  2. What happens when a dependency is down or slow? Timeouts, retries, and whether a retry is safe to apply twice.
  3. How do you know it's working? What you'd measure, and what you'd look at when a number moves.
  4. Why this and not the other thing? The trade-off, stated as a decision rather than a shrug. Talking about trade-offs is the technique that carries all three rounds.

This is why an engineer with ten years of Java can pass a Go interview and a bootcamp graduate with six months of Go usually can't. The language-specific layer is a few weeks of study. The layer underneath is the job.

How to tell which round you're in

Read the job description for what it complains about, not what it lists. A posting that talks about throughput and services is usually a Go round. One that names a framework, an application server and a cloud vendor is usually Java. One that mentions data pipelines, ML tooling or a small team shipping fast is usually Python.

Then ask the recruiter directly: which language will the technical round be in, and will I be writing code or talking about it? Both answers change what you should do with your remaining hours, and recruiters answer this honestly almost every time.

If you're switching languages

Spend your preparation on the concurrency model and the error model of the target language, in that order. They're where the idioms differ most and where a non-native answer is most audible. A Python engineer moving to Go has to stop thinking of concurrency as a library choice. A Go engineer moving to Java has to get comfortable with a framework doing things on their behalf. A Java engineer moving to Python has to notice how much the type checker was catching.

Then rehearse out loud in the target language, because vocabulary is half of sounding native. Reading about the differences is slower than sitting one: pick the language on the practice setup screen and the follow-ups land on exactly the words you chose, in the idiom you chose them in.

Common questions

I know two of these. Which should I interview in?

The one the job is in, if you can hold your own in it. Interviewing in your strongest language for a role written in another mostly moves the same question to a later round. If they let you choose and both are close, pick the one whose concurrency model you can explain without hedging.

Will they reject me for never having used Go professionally?

For a senior backend role, usually not. Teams hiring experienced engineers expect a few weeks of ramp-up. What they won't forgive is claiming fluency you don't have, because the follow-up finds it immediately.

Is the Java round more algorithm-heavy?

Not because of the language. It correlates with company type instead: large product companies run algorithm stages whatever the stack. Ask the recruiter rather than assuming from the language.

How much framework knowledge do I need?

Enough to explain what the framework does for you and what it costs. Spring, Django, FastAPI or a Go router: the question is nearly always what happens to a request between arriving and reaching your handler, and where you'd put something that has to run for every request.

Do these rounds ask about deployment and operations?

Increasingly, yes, and it's often where seniority is decided. How the service starts, what happens to in-flight requests during a deploy, and what you look at first when it misbehaves are fair game in all three languages.

PythonGoJava

Keep reading

All posts