2026-01-18
Technical Phone Screen Questions for Go Developers
Technical Phone Screen Questions for Go Developers
A 30-minute phone screen can make or break your hiring decision. With Go developers, you need to move fast—assess core language fundamentals, concurrency patterns, and practical problem-solving without wasting time on trivia.
This guide gives you a battle-tested framework for screening Go developers, complete with follow-up questions, red flags, and scoring guidance. Whether you're hiring for your first Go engineer or scaling a team, these questions filter for actual competence.
Why Go Phone Screening Is Different
Go is deliberately minimal. There's no inheritance, no magic operators, and a standard library that covers 80% of real-world needs. This means a good Go developer stands out not through language tricks, but through clear thinking about concurrency, error handling, and system design.
Phone screening Go developers differs from screening Python or JavaScript developers because:
- Concurrency is mandatory. Most Go jobs involve goroutines. You can't hire a Go engineer who doesn't understand channels and goroutine leaks.
- Interface design matters more. Go's compositional approach (embedding, interfaces) separates senior engineers from beginners.
- Performance assumptions vary. Go devs need to think about allocations, goroutine overhead, and when to use buffered channels.
A weak Go developer will hemming and haw about goroutines. A strong one explains tradeoffs with confidence.
The 30-Minute Phone Screen Structure
Before diving into specific questions, here's the rhythm that works:
- Warm-up (2 minutes): Role, team, codebase size
- Fundamentals (8 minutes): Error handling, interfaces, concurrency basics
- Problem-solving (15 minutes): Live coding or architecture question
- Your turn (5 minutes): They ask questions
This keeps energy high and filters effectively. You're not testing memorization; you're testing judgment and communication.
Section 1: Fundamentals Questions
Question 1: "Explain the difference between a goroutine and a thread, and why it matters."
What you're listening for: - Do they know goroutines are M:N multiplexed (many goroutines, few OS threads)? - Can they explain context switching overhead? - Do they understand scheduler preemption?
Good answer markers: - "Goroutines are lighter—thousands can run on a single thread" - "The Go runtime schedules them, not the OS" - "You can spawn millions; threads you can't"
Follow-up if weak: "So if I spawn 100,000 goroutines, what happens?"
Expected answer: They should explain that the Go runtime has a work-stealing scheduler. If they say the OS "can't handle it" or talk about thread pools, they don't have production Go experience.
Red flag: "I think goroutines are like coroutines" or vague hand-waving about concurrency.
Question 2: "Walk me through how channels work. What's the difference between buffered and unbuffered channels?"
What you're listening for: - Synchronization understanding (unbuffered = blocks until both ends ready) - Buffering mechanics and deadlock risk - When to use each
Good answer markers: - "Unbuffered channels block the sender until a receiver is ready" - "Buffered channels hold N values; sender only blocks when full" - "Unbuffered is for synchronization; buffered is for decoupling"
Follow-up: "What happens if you close a channel that still has goroutines reading from it?"
Expected answer: They should mention:
- Panic if you send on a closed channel
- Receivers can still drain from a closed channel
- Receivers need a pattern to detect closure (the ok idiom)
Red flag: "I'm not sure" or confusing channels with queues.
Question 3: "How do you handle errors in Go? What's the philosophy?"
What you're listening for:
- Understanding of explicit error handling (not exceptions)
- The if err != nil pattern and why it's intentional
- Wrapping errors and context
Good answer markers:
- "You return errors as values"
- "Every function that can fail returns an error as the last return value"
- "Go avoids hidden control flow—errors are explicit"
- Mentions fmt.Errorf, errors.Is(), or errors.As() for modern Go
Follow-up: "Should you panic in production code? When?"
Expected answer: Panic only for true programmer errors (nil dereference, invariant violations), not for recoverable failures. If they're wrapping panics in a web server, that's a red flag.
Red flag: Treating errors like exceptions or being vague about error propagation.
Question 4: "What's an interface in Go, and how is it different from interfaces in Java or TypeScript?"
What you're listening for: - Structural vs. nominal typing - Implicit satisfaction (no implements keyword) - Composition over inheritance mindset
Good answer markers:
- "Interfaces are satisfied implicitly by any type with matching methods"
- "A type doesn't declare which interfaces it implements"
- "It's duck typing but type-safe"
- Can give an example: io.Reader is satisfied by any type with a Read() method
Follow-up: "Design me an interface for a thing that can fetch data. What methods?"
Expected thinking:
- Something like Fetcher with a Fetch(ctx Context, url string) ([]byte, error) method
- Single responsibility (one method or closely related methods)
- Uses context.Context for cancellation
Red flag: Treating Go interfaces like Java—listing all implementations or overthinking the "hierarchy."
Section 2: Concurrency & Channels
Question 5: "Write a function that spawns 10 goroutines, each incrementing a counter, and returns the final count. What could go wrong?"
This is a medium-complexity live coding question. Don't expect perfect syntax; listen for the pattern.
What you're listening for: - Do they recognize race conditions? - Do they use a mutex, channel, or atomic operation? - Do they wait for goroutines to finish?
Weak answer (race condition):
var count int
for i := 0; i < 10; i++ {
go func() {
count++
}()
}
return count // Wrong!
Good answer (one of three patterns):
Pattern 1: Mutex
var count int
var mu sync.Mutex
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
count++
mu.Unlock()
}()
}
wg.Wait()
return count
Pattern 2: Channel (slower, but shows channel understanding)
results := make(chan int, 10)
for i := 0; i < 10; i++ {
go func() {
results <- 1
}()
}
count := 0
for i := 0; i < 10; i++ {
count += <-results
}
return count
Pattern 3: Atomic (best for simple counters)
var count int64
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt64(&count, 1)
}()
}
wg.Wait()
return count
Follow-up: "Which pattern would you use in production and why?"
Expected reasoning: - Atomic for simple counters (no allocations, fastest) - Mutex for complex shared state - Channels only if you're already communicating
Red flag: Ignoring the race condition entirely, or using a channel when a mutex would be simpler.
Question 6: "Design a worker pool pattern. You have 100 jobs and 5 workers. How do you implement it?"
What you're listening for: - Do they understand producer/consumer? - Can they balance channel buffering? - Do they handle graceful shutdown?
Good high-level answer:
- Create a channel for jobs (e.g.,
jobsChan := make(chan Job, 100)) - Spawn 5 worker goroutines, each reading from the channel
- Send 100 jobs into the channel
- Close the channel when done (workers drain remaining jobs)
- Use a
WaitGroupto know when all workers finish
Follow-up: "What if a worker panics? How do you recover?"
Expected answer: Either:
- Recover in each worker's loop: defer func() { if r := recover(); r != nil { log.Printf("worker panic: %v", r) } }()
- Or (more common in production): don't let workers panic—handle errors at the job level
Red flag: Oversimplifying to "just use goroutines" without channel patterns, or not thinking about cleanup.
Question 7: "What's a goroutine leak, and how do you prevent one?"
What you're listening for: - Understanding of leaking resources - Practical prevention patterns
Good answer markers:
- "A goroutine leak is a goroutine that never exits, holding memory"
- "Common cause: goroutine blocked on a channel that never receives"
- Prevention: use context.Context for cancellation, close channels properly
- Example: select { case <-done: return; case val := <-ch: ... }
Example scenario to follow up: "You have a goroutine reading from a channel. The caller stops reading. What happens?"
Expected answer: The goroutine blocks on the send side forever. Prevention: the caller should signal via a done channel that the reader can exit.
Red flag: "I've never heard of goroutine leaks" or vague answers about memory.
Section 3: Architecture & System Design
Question 8: "Design a simple HTTP service that calls an external API with a timeout. What Go patterns would you use?"
What you're listening for:
- Knowledge of context.Context and timeouts
- Error handling at the HTTP level
- Practical HTTP patterns in Go
Good answer structure:
1. Use context with timeout: ctx, cancel := context.WithTimeout(...)
2. Pass ctx to http.NewRequestWithContext(ctx, ...)
3. http client respects the context and times out
4. Check for context.DeadlineExceeded to differentiate from other errors
5. Use defer cancel() to clean up
Follow-up: "What if the external API is slow? How do you prevent cascading failures?"
Expected reasoning: - Circuit breaker pattern (stop calling if it's failing) - Backoff and retry - Short timeouts to fail fast
Red flag: Not mentioning context.Context at all, or showing timeout without proper error handling.
Question 9: "What packages from the standard library do you use most? Why?"
What you're listening for: - Real-world Go experience - Understanding of stdlib strengths
Typical strong answers include:
- context — for cancellation and deadlines
- fmt — logging and formatting
- errors — error handling
- sync — mutexes and WaitGroups
- io and bytes — data handling
- encoding/json — API work
- net/http — web services
Red flag: Naming packages they've barely used, or gaps that suggest limited production experience (e.g., never used context in production Go).
Question 10: "Tell me about a Go project you've built. What was hard? What would you do differently?"
What you're listening for: - Real experience with Go's constraints and strengths - Self-reflection and growth mindset - Honest assessment of decisions
Good answer markers: - Specific project (not hypothetical) - Concrete challenge: "Goroutine management at scale" or "JSON unmarshaling was the bottleneck" - Thoughtful reflection: "I'd use sync.Pool to reduce allocations" - Shows learning: "I didn't understand channels at first, but..."
Red flag: "I haven't built anything in Go" or "No, it was perfect" (no self-reflection).
Scoring Guide
Use this simple rubric:
| Score | What It Means |
|---|---|
| 5 | Perfect or near-perfect answer; shows deep Go experience |
| 4 | Good answer; might need minor prompts; solid production experience |
| 3 | Adequate answer; understands concepts but may lack depth or confidence |
| 2 | Weak answer; gaps in knowledge or vague explanations |
| 1 | Wrong or no answer; misunderstands core concepts |
| 0 | Doesn't attempt to answer |
Passing thresholds: - Senior hire (5+ YOE): Average of 4+ - Mid-level (2-5 YOE): Average of 3.5+ - Junior/intern: Average of 2.5+
Red Flags & Deal-Breakers
| Red Flag | What It Suggests |
|---|---|
| Can't explain goroutines vs. threads | Lacks core Go knowledge |
| Treats channels like queues; doesn't understand sync | Hasn't built concurrent systems |
| Ignores race conditions | Will ship bugs; doesn't run go test -race |
Never heard of context.Context |
No production experience with cancellation |
| Panics liberally in production code | Misunderstands error handling philosophy |
| Can't name stdlib packages | Limited real-world use |
| Defensive or evasive about gaps | Poor learning mindset |
Green Flags & Strengths
| Green Flag | What It Suggests |
|---|---|
Mentions sync/atomic for simple counters |
Understands performance nuances |
Uses context.Context naturally |
Experienced with production concerns |
| Can debate mutex vs. channel tradeoffs | Thinks about design, not just syntax |
Brings up error wrapping and errors.Is() |
Stays current with Go evolution |
| Discusses goroutine lifecycle and cleanup | Thinks about resource management |
| References a real project with specifics | Actually ships Go code |
Common Mistakes in Go Phone Screens
Mistake 1: Asking syntax questions
"What does := do?" wastes time. Focus on behavior and tradeoffs.
Mistake 2: Not clarifying concurrency expectations If your role uses goroutines heavily, make concurrency the focus. If it's a CLI tool, you can relax here.
Mistake 3: Accepting "I'll just Google it" for fundamentals You can Google syntax. You can't Google "how do I prevent goroutine leaks?"
Mistake 4: Not listening to confidence level A candidate saying "I'm not 100% sure, but my instinct is..." and explaining reasoning is stronger than false confidence.
FAQ
What if a candidate doesn't know the answer to a concurrency question?
Ask a follow-up: "How would you learn about it?" or "What tools would you use to debug it?" (answer: go run -race, pprof, etc.). Learning ability matters more than current knowledge for junior hires.
Should I ask about goroutine pooling libraries like ants?
Only if your stack uses them. For general screening, focus on stdlib patterns. If they mention third-party libraries unprompted, that's a green flag for staying current.
How do I handle a candidate who freezes or gets nervous?
Give them a moment. Say: "No pressure—walk me through your thinking." Nervous candidates often relax once they start explaining. A strong engineer under stress is still a strong engineer.
What if they give a solution that works but isn't idiomatic?
Good. Ask: "How would a senior Go engineer approach this differently?" This tests self-awareness and willingness to learn.
How long should I spend on each section?
Adjust based on seniority. For a junior, spend more time on fundamentals and less on system design. For a senior, flip it—they should nail fundamentals quickly.
Next Steps: Finding Go Developers Worth Screening
These questions work best when you're screening qualified candidates. The hard part is finding them in the first place.
Hire Go Developers using real signals: analyze their GitHub contributions, check their actual concurrency patterns, and see how they structure projects.
Or explore our Guides for screening strategies across other languages and roles.