Konrad Reiche’s personal website—Staff Software Engineer at Reddit, passionate about building scalable backend infrastructure and designing impactful software abstractions.
Let’s talk about nil pointer checks in Go. You want to prevent panics in production, but that doesn’t start with a deferred recover . It starts with defensive programming. Check your inputs, check your bounds, and check pointers for nil before dereferencing them. I’ve started to see more nil checks in Go code. In the right place, they are necessary for writing safe code. In the…
I first encountered PID controllers while working with Donovan Baarda on a cache implementation for a GopherCon talk in 2024, where he proposed using one as a feedback mechanism to regulate eviction rate efficiently. PID controllers belong to a broader family of feedback control mechanisms that stabilize systems under changing conditions. With relatively simple rules, they can keep complex systems…
In 2024, I reviewed 233 GopherCon talk proposals as part of the review committee. As a reviewer, I had to judge proposals solely on what’s written, not assume anything, and identify what value the talk will deliver to the audience. That last question was missing from most submissions. Even proposals with detailed outlines and obvious effort forgot to provide the critical piece: why should a…
Ever since I got the Pixel 9 Pro Fold, I’ve been curious about whether it could double as a full-on development device, especially for light travel. With the arrival of the Android Linux Terminal application , a full Debian-based Linux Virtual Machine running on ARM, I figured it was time to give it a shot. I paired it with the NuPhy Air60 V2 external keyboard, and voilà: a pocket-sized…
If you’ve ever been part of a post-incident review (postmortem), you’ve probably heard that postmortems should be blameless. And if you’ve grown up in an environment where fault-finding is the norm, embracing blamelessness can feel awkward, even unnatural. At the core of a blameless postmortem is a simple idea: the human is not the root cause. We build complex, distributed…
Writing a generic protobuf writer in Go is straightforward. We simply use proto.Marshal with the protobuf message because proto.Marshal expects the proto.Message interface, which all generated protobuf messages implement. However, when it comes to reading serialized protobuf data into a specific Go type, historically, we had to specify the type explicitly: var post pb . Post if err := proto .…
When it comes to code reviews, I’ve found that my most helpful feedback starts with checking the code out locally. The limited view on GitHub often falls short; it lacks full context and can’t match the navigability of a local environment. While you can expand the surrounding code on GitHub, it’s tedious and limited to nearby lines. I usually jump to function declarations, usage…
If you write your Go tests against real dependencies like Redis, you may have encountered a common problem. Tests running in parallel or across multiple packages can inadvertently use the same keys. This often leads to intermittent failures when tests simultaneously read from or write to these shared keys. One way to avoid this is by ensuring each test uses a unique set of keys. However, tracking…
In my previous post , I highlighted two common misuses of interfaces in Go: interfaces prematurely introduced for abstraction and interfaces created solely to make testing easier. The latter, in particular, deserves some hands-on examples to showcase a structured solution. In this post, we’ll dive into an example project and explore how we can move away from using interfaces for dependencies…
In Go, interfaces are often misused in two ways. First, interfaces are introduced prematurely by following object-oriented patterns from languages like Java. While well-intentioned, this approach adds unnecessary complexity early in the development process. Second, interfaces are created solely to support testing, a practice common in languages like Python that also relies heavily on mocking…
Initially, I was at odds with Go’s parallel benchmark utility function—the documentation on b.RunParallel is somewhat sparse, but it is a tool that makes benchmarking in Go much easier. RunParallel runs a benchmark in parallel. It creates multiple goroutines and distributes b.N iterations among them. The number of goroutines defaults to GOMAXPROCS. func Benchmark ( b * testing . B ) { b .…
Using the internal package in Go is a common way to limit your public API surface . The Go toolchain recognizes it and prevents external code from importing it. Typically, you place internal packages at the root of your repository or Go module to restrict external imports. However, I’ve recently discovered another valuable application for internal packages: maintaining import patterns within…
Starting a goroutine is as easy as adding the go keyword in front of a method, but managing the lifecycle of a goroutine is not. If you only need to start a few goroutines and wait for their completion, you are off the hook thanks to sync.WaitGroup . However, what if a goroutine has to run for a specific duration or repeatatly in a loop until the initiating code terminates? Does it matter? After…
Using redis-cli with Redis cluster may differ from using it against a single instance. Generally, read and write operations for keys work fine as long as cluster mode is enabled by using the -c option. However, certain commands are specific to a particular Redis node, such as SCAN or FLUSHDB , where the cluster mode option is silently ignored and the command is only executed against the node the…
The simplicity of Go’s error handling system is a big strength. What seems repetitive is a continuous prompt to the author of the code: should I handle the error or return it? Most of the time the error will be returned. At some point in the caller chain this decision might change to handling the error, for example by logging it: here we also stop passing the error further up. An error log…
There are different ways of separating integration tests from your unit tests in Go. After discovering too many issues with some of the approaches I have settled with the following. func TestDatabase ( t * testing . T ) { integrationTest ( t ) // ... } func integrationTest ( t * testing . T ) { t . Helper () if os . Getenv ( 'INTEGRATION' ) == '' { t . Skip ( 'skipping integration tests, set…
There are good video editors for Linux but every time I find myself in need of editing a video I end up spending more time learning how to use the program than benefiting from it. Behind the scenes they use ffmpeg . Learning how to use ffmpeg is a much more transferable skill, for example if you want to write a service which encodes GIFs to videos or a service to crop images. At our most recent…
Correctness in concurrent systems comes down to the question: how sure can we be of the state we are observing? For shared resources we may want to prevent concurrent writes and reads to a resource only one client should hold a lock to avoid data races. Locks as a concurrency primitive in programming languages are well known and safe to use when applied correctly. Locks in distributed systems are…
Dave Cheney famously said it: cgo is not Go. You’re not writing a Go program that uses some logic from a C library, instead you’re writing a Go program that has to coexist with a belligerent piece of C code that is hard to replace, has the upper hand negotiations, and doesn’t care about your problems. With cgo, C calls the shots, not your code. Today, I had to make this experience firsthand…
As I have started to dive into the world of Docker I found myself using a new plethora of commands in my terminal. Thanks to a combination of my terminal multiplexer ( tmux ), history search ( reverse-i-search ) and fuzzy finder ( fzf ) it is relatively easy to retrieve previous commands. When you need to replay a combination of commands this starts to become inefficient. Here is a collection of…
Growth. Hacking. To be frank, I found Growth Hacking one the biggest buzz words in the last couple of years — overused and overvalued. Now, where the heat around it has died a little bit I find this topic much more approachable. It was used in the past to spawn a lot of debate, yet the goal to stimulate fast growth in tech companies persists. This is an overview and a collection of practices I…
Since most of the Java code I wrote in the past was on Android I was not able to enjoy too many Java 8 features yet. Though recently I wrote a microservice in Java using Spring Boot where I could make full use of lambdas and functional interfaces. The following method, for instance, returns the sum of all transactions for a specified instance by traversing their children. @RequestMapping ( value =…
Taking ownership, respectively responsibility has been a major requirements in startup jobs for a long time; in particular, code ownership. Cunningham & Cunningham on c2.com , one of the earliest Wikis, quotes the following sentence with regards to code ownership: Each code module in the system is owned by a single developer. Except in exceptional and explicit circumstances, code may be modified…
Ruby on Rails applications are modelled around active record yet what if your application is based on a domain which needs to be provided in a programmatic way? In other words, your application, controller and views stand on a fixed set of Ruby classes yielding the context. In a manual fashion one would implement this by creating controller and views for each specific class. Assuming that the…
The Secure Shell (ssh) is a universal tool when it comes to accessing machines remotely. Mostly known for opening a remote terminal environment there are much more possibilites hidden in its server functionality. One of them is tunneling. Tunnelings allows a remote host to function as a proxy server. This comes in handy when developing on a network infrastructure that has a DMZ. A gateway server…
Sidekiq is a Redis-backed Ruby framework for moving asynchronous tasks into background processes. Using threads instead of forks it claims to be much more memory efficient in contrast to Resque . Redis, a key-value store, is used for storage of the jobs. The Sidekiq server processes messages as a multi-threaded process. This setup might come in handy for the production environment, but if you are…
For my last student research project I wanted to model classes with a set of fixed values. Enum types are a great alternative when working with constant values, especially when they are supposed to encapsulate more than just the value itself. By declaring additional fields or methods the enum type can be enriched with a lot of information. What I did not know so far, is the fact, that it is also…