Posts
2026
Go’s simplicity makes it easy to write code, but architecture questions — how to structure a codebase, how to decouple components, how to handle dependencies — consistently come up in senior-level interviews.
Python is the default language for inference servers, and for good reason: PyTorch, HuggingFace, and most ML tooling are Python-first. But if the rest of your stack is Go, you end up with a Python sidecar just to call model.forward(). That sidecar needs its own container, its own health checks, its own deployment pipeline, and its own debugging story.
Few bugs in Go are as disorienting as this one: you return nil from a function, check the result against nil, and the check fails. No type assertion panic, no runtime error — just a quiet wrong answer that sends you down a debugging rabbit hole.
A goroutine leak is one of the most insidious bugs in Go. Unlike a memory leak in C, nothing crashes. No panic, no OOM killer. Your service just slowly grows in memory and CPU usage over hours or days until it falls over — or someone notices the goroutine count in a dashboard.
Go’s error handling is explicit by design: errors are values, returned like any other value, checked by the caller. It is one of the most frequently discussed topics in Go interviews because it differs so sharply from exception-based languages.
defer is one of Go’s most useful features and one of its most misunderstood. The documentation is precise: a deferred call runs when the surrounding function returns — not when the surrounding block or loop iteration ends. That single sentence is responsible for resource leaks, silent data corruption through named returns, and unnecessary performance overhead that persists until you know to look for it.
Two functions. Nearly identical code. One puts your variable on the stack; the other sends it to the heap, adding GC pressure every time it runs. You cannot tell which is which by reading the code — you need to ask the compiler.
Arrays and slices are closely related but behave very differently. Confusing them is a common source of bugs and a reliable interview topic. For a deeper runtime dive, see Slice internals.
Maps are Go’s built-in hash table. They are fast and easy to use, but they have several sharp corners that interviews frequently probe.
Slices are the bread and butter of Go programming. Most developers use them daily without thinking twice — and that comfort is exactly where subtle, load-dependent bugs come from. This article pulls back the curtain on how slices are represented in memory and explains the class of bug that emerges when two slices quietly share the same underlying array.
When goroutines share memory, you need synchronization. Go’s sync package provides the primitives for it. Prefer channels for ownership transfer; use sync when multiple goroutines must touch the same state.
Channels are Go’s primary mechanism for passing data between goroutines. The mantra is: do not communicate by sharing memory; share memory by communicating.
Goroutines are Go’s unit of concurrency. They are the first thing interviewers ask about when the topic turns to concurrency.
MXFP4 quantization is a microscaling, 4-bit floating-point compression scheme designed to shrink the memory footprint of deep-learning models without hurting accuracy.
Interfaces are one of the most distinctive parts of Go’s type system and reliably show up in interviews. The core idea is small but the implications go deep.
2025
In the Go runtime, the scheduler is the engine that manages how thousands of goroutines are multiplexed onto a limited number of operating system threads. To ensure system responsiveness and prevent “resource hogging,” Go employs a mechanism called preemption.
You run a model in INT8 and it is 30% faster than FP32. You run the same model in INT8 with a different framework — same hardware, same batch size — and it is 2% faster. You run it again with a different calibration dataset and the accuracy drops by 4 points. Quantization is not one thing.
Your quantized model is listed at 4 GB on the model card. You load it onto an NVIDIA Jetson Orin with 8 GB of unified memory. It OOMs at 3.2 GB loaded. You reduce batch size to 1. Still OOM. You switch to INT4 weights. Finally it runs — but the throughput is half of what you expected.
You have a timer loop that resets after each event. The code looks right. The tests pass consistently. Then, once every few hours in production, a value appears in the channel that was not supposed to be there. It corrupts state in a way that is impossible to reproduce locally, because it requires a race window measured in nanoseconds.
You set GOMAXPROCS=8 on a 16-core machine because you read that matching CPU count improves throughput. Your CPU-bound service gets slower. The goroutine count on the dashboard rises steadily. Nothing in the logs explains it, and the Go documentation does not mention this case.
You copy a struct to pass it to a helper function. The mutex inside is now two independent locks protecting the same data. Your race detector says nothing. Your tests pass. Production disagrees — intermittently, and badly.
