Buy Me a Coffee
Illustration of efficient concurrency testing with Go using synctest

[Golang] Mastering Concurrency Testing with `synctest` package

Introduction Testing concurrent code in Go can be challenging, especially when dealing with timing issues. One common problem is ensuring goroutines, Go’s lightweight threads, have finished their tasks. Traditional techniques often incorporate time.Sleep, but this can slow down tests or make them unreliable. Fortunately, Go 1.25 introduced the testing/synctest package into the standard library (after first being available experimentally in Go 1.24). It helps tackle these issues by providing a deterministic way to test concurrent code without the usual timing trade-offs. ...

Go Defer Trap Avoided

[Golang] Avoid Using `defer mu.Unlock()` Inside Loops

In Go, using a mutex with defer might seem like an elegant and safe way to manage your code by ensuring resources are properly released. However, a common mistake lurks when this pattern is used inside loops. When working with mutexes, never do this: func broadcast(ctx context.Context, msgCh <-chan Message) { for { select { case msg := <-msgCh: s.mu.Lock() defer s.mu.Unlock() // ❌ Avoid this // Use the shared resource here case <-ctx.Done(): return } } } This seemingly harmless pattern can cause unexpected behavior and should be avoided. Let’s look into why this happens and how to handle it correctly. ...

Golang API Design - Illustration depicting a clear and safe API design for Go

[Golang] Stop Returning `(nil, nil)` in Go: A Small API Design Choice That Prevents Big Bugs

When designing Go APIs, you might think it’s harmless to return (nil, nil) when an object isn’t found. Many developers do this because it feels like “not found” shouldn’t be treated as an error. However, this approach often leads to one of the most frustrating runtime crashes in Go: panic: invalid memory address or nil pointer dereference In this post, we’ll cover: The problem — how (nil, nil) breeds fragile code Why this design creates real-world headaches Two solutions: Best practice (recommended): return a predefined error instead Alternative pattern: use an explicit existence flag An evolved, safer version of the code The goal isn’t just to fix mistakes, but to enhance API design to prevent misuse down the line. ...

Golang errors.Join illustration

The Pragmatic Way to Handle Multiple Errors in Go (Before and After Go 1.20)

Introduction For many Go developers, a recurring challenge has been: “What is the right way to handle multiple errors?” Whether it’s running several cleanup steps, processing batches of data, or validating various inputs, ensuring errors are handled correctly and efficiently has been crucial. Before Go 1.20, developers did not have a unified approach; each team created its own solution, often leading to awkward, unidiomatic, or even incorrect patterns. With Go 1.20, we now have a standard, pragmatic solution: errors.Join. This article will explore why older techniques were problematic, how the Go team designed a better approach, and how to apply this new solution effectively in your code. ...

DigitalOcean Referral Badge
Sign up to get $200, 60-day account credit !