Buy Me a Coffee
Illustration depicting simple and elegant Go code with clean lines

[Golang] Writing Elegant Go Code Without Overengineering It

If you’ve been working with Go for a while and find your code resembling a plate of spaghetti, rest assured you’re not alone. This is a common challenge many developers encounter over time. The issue often isn’t a lack of design patterns or frameworks, but rather the misuse of abstractions at the wrong moments. Writing elegant Go code is about increasing readability, not demonstrating cleverness. This post outlines essential principles to transform complicated and tangled Go code into a cleaner and more maintainable form—without drifting into complex “enterprise abstraction soups.” ...

Illustration depicting the concept of dependency inversion in software design

[Golang] Mastering Dependency Inversion: Keep Your Go Code Clean

Dependency inversion is a fundamental principle in software design that enhances code cleanliness, maintainability, and extensibility. While not exclusive to Go, the way it manifests in this language is particularly accessible and effective. At its heart, dependency inversion asserts that high-level components should not rely directly on low-level modules. Instead, both should depend on abstractions, fostering a more adaptable architecture. In practical Go development, this means crafting your business logic to interface with small abstractions that express what functionality is needed rather than focusing on how that functionality is implemented. This post dives into how to leverage this principle in Go, highlighting potential pitfalls and offering concrete examples to demonstrate correct implementation. ...

Understanding TCP in Go - Common Misconceptions and Practical Examples

[Golang] Understanding TCP: Debunking Misconceptions with Practical Examples

TCP might seem straightforward, especially when using Go. You set up a net.Conn, call Write to send data, Read to receive it, and everything just seems to work. It’s straightforward, minimal, and very Go-like. However, this simplicity can lead to misunderstandings because the details beneath the surface are easy to overlook. This blog post aims to demystify the real workings of TCP using practical examples, tackling common myths, all within the context of Go development. ...

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. ...

Conceptual illustration of cookies, sessions, and JWT authentication flow

How Web Authentication (Cookies, Sessions, JWT) Actually Works

Authentication on the web often feels confusing not because it is complicated, but because its core ideas are rarely explained in a clean order. This post builds that order. We will start from the nature of the web itself, explain cookies and server-side sessions as a single coherent model, then expand outward to JWT and why it fits modern distributed systems. The goal is not to overwhelm you, but to give you a mental model you can reuse. ...

OneClickTLS online certificate generator

Introducing OneClickTLS: Generate Self-Signed TLS and mTLS Certificates Instantly

Introducing OneClickTLS: Generate Self Signed TLS and mTLS Certificates Instantly If you have worked with Kubernetes, Docker, microservices, or local HTTPS development, you already know how frustrating it is to generate self signed TLS certificates. Searching for OpenSSL commands, adjusting SAN values, fixing errors, and repeating the entire process again and again. After dealing with this pain for years, I finally built a tool that removes all the friction: https://oneclicktls.com ...

Debugging Go Programs in VSCode with Kubernetes

[Kubernetes] How to Debug Programs That Use the Kubernetes Client SDK in VSCode (Golang Example)

When you first work on a Go project that uses the Kubernetes client SDK, you might feel lost about how to debug it on your local environment. Don’t panic. It’s actually very simple once you understand what’s happening behind the scenes. I’ll walk you through how to make it work using VSCode as an example. The Common Confusion When your program is designed to run inside a Kubernetes cluster, it usually connects to the cluster using rest.InClusterConfig(). This configuration relies on the ServiceAccount token mounted at /var/run/secrets/kubernetes.io/serviceaccount/token. When you run the same program locally, that path doesn’t exist, and the SDK will fail to initialize with an error like: ...

Observer pattern illustration depicting a central subject with multiple observers connected

[Golang] Exploring the Observer Design Pattern with Code Example

Introduction Today, we will dive into understanding the Observer Design Pattern with a Golang code example. This pattern is a cornerstone of software design, promoting flexibility and reuse in code by managing dependencies effectively. What Is the Observer Pattern? The Observer pattern defines a one-to-many dependency between objects, ensuring that when one object (the Subject) changes its state, all its dependents (Observers) are automatically notified. This pattern is pivotal in creating an efficient and decoupled architecture. ...

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