Provyn Prep · 8 min read

How to pass the Provyn Go assessment

The Go assessment targets the concurrency model and idioms that make Go different — not syntax memorisation. You need to know what goroutines and channels actually do, not just that they exist.

What you will be tested on

  • Goroutines: scheduling, goroutine leaks, WaitGroups
  • Channels: buffered vs unbuffered, select, done-channel pattern
  • Interfaces: implicit implementation, empty interface, type assertions
  • Error handling: sentinel errors, error wrapping, errors.Is/As
  • sync package: Mutex, RWMutex, Once, atomic operations
  • Context: cancellation propagation, deadlines, value passing

What the assessment tests

The Go assessment is built around the concurrency primitives that make Go distinctive. Questions test whether you know when a goroutine leaks and why, how channels communicate between goroutines, and how the select statement avoids blocking.

The heaviest-weighted area is the done-channel pattern and context cancellation. Know how to write a goroutine that listens on a done channel and exits cleanly when the channel is closed. Know how to propagate context cancellation through a call stack.

Goroutines and goroutine leaks

A goroutine leaks when it is started but never exits. Common causes: blocking on a channel send with no receiver, blocking on a channel receive with no sender, and waiting on a WaitGroup that is never Done()d. The assessment will show you a function with a goroutine that leaks and ask you to identify and fix it.

The done-channel pattern: pass a chan struct{} as a done channel. Close it to signal all listening goroutines to exit. Use select with a done case and the work case to pick whichever is ready. If done fires, return — never block after shutdown is signalled.

Channels: buffered vs unbuffered

Unbuffered channels block the sender until a receiver is ready and block the receiver until a sender is ready. They are a synchronisation point, not just a data pipe. Buffered channels allow the sender to send up to the buffer capacity without blocking.

The select statement picks the first case that is ready without blocking. If multiple cases are ready simultaneously, it picks one at random. Use select with a default case for a non-blocking channel operation. The assessment will show a select and ask what happens — check every case to see which can unblock.

Interfaces and error handling

Go interfaces are satisfied implicitly — no 'implements' keyword. A type satisfies an interface if it has all the methods with matching signatures. The empty interface (interface{} or any) is satisfied by everything but gives you nothing without a type assertion.

Error wrapping: fmt.Errorf("context: %w", err) wraps err so that errors.Is and errors.As can unwrap through the chain. The assessment will ask you to identify whether errors.Is can find a specific error type — it can if the error chain contains it; it cannot if the error was overwritten without wrapping.

Three-day prep plan

Day one: implement a worker pool from scratch: a fixed number of goroutines reading jobs from a channel, with WaitGroup to wait for all to finish and context cancellation to stop early.

Day two: run the practice assessment. Note the concurrency questions where you hesitated.

Day three: read the sync package documentation. Know Mutex (exclusive access), RWMutex (multiple readers OR one writer), and Once (initialise exactly once). The assessment will ask which to use in a given scenario.

Ready when you are

Take the Go assessment

Sixty minutes. One credential. Free tier — no card required.

Last updated 2026-05-01.