RSSAmplifier

Blog

Aran Wilkinson

Software engineer — Go, distributed systems, Google Cloud. Based in Huddersfield, UK.

aran.devRSS feed ↗48 posts

Latest posts

Owning the Harness

Over the past year I've started noticing something in the conversations I have with others when talking about AI usage at work. Ask someone how their company is handling AI tooling and you'll almost always get one of two answers. Either they've gone all in. Every engineer gets a Copilot or Cursor or Claude licence, token budgets don't exist, and leadership has basically said…

Consuming a real-time feed reliably

When you're ingesting a continuous external stream — live transit data, market ticks, IoT telemetry, whatever — the consumer's job and the job of interpreting what was consumed are tempting to bundle together. They shouldn't be. This is the pattern behind the Darwin Kafka ingestion in Headcode , my UK rail data API, though it generalises well beyond rail data: a dumb, fast consumer…

Headcode started as a project to learn UK rail data

It now has eight live endpoints , a tiered pricing page and an alpha banner warning people the schemas might still move under them. None of that was the plan. The plan was to understand how UK rail data actually fits together, and to work out how to use an LLM properly on something real instead of a toy. The product is just what happened while I was doing that. I'm still not sure it becomes a…

Resume

Introducing Headcode: A Unified API for UK Rail Data

UK rail data is brilliantly open and freely available. It is also completely fragmented across dozens of discrete, historically siloed sources. If you want to build an application that tracks trains, you have to piece together obscure feeds from the Rail Data Marketplace, Network Rail Open Data, NaPTAN, and the Office of Rail and Road. Much of this fragmentation goes back to the legacy of British…

Introducing jjw: a workspace manager for jj

I've just released jjw , a small command line tool for managing jj workspaces. The short version is that jjw gives me a nicer workflow for creating, switching between, and deleting isolated jj workspaces. The slightly longer version is that I wanted a reliable way to run multiple coding agents in parallel without them trampling over each other's working copies, local state, or setup. It…

Why I built a reference Go project (and taught an AI agent to clone it)

I get asked about how to structure a Go project often. Not the big architectural questions about microservices versus monoliths, but the mundane stuff: where does the config go, why isn't there a pkg/ directory, what's the difference between internal/books/ and internal/database/books/ . I used to answer with a wall of text. Then I started linking to…

Now

living in Huddersfield, UK working remotely as a Golang Engineer our little one is coming up on their first birthday, which has been the best and most tiring year of my life exploring UK rail data and building Go services to process real-time train information with Kafka and PostgreSQL ( wrote about it here ) planning to rework parts of my home smart lighting project, which has been on hold for a…

How I lost a database and learned to actually use AI

A while back I was working on a personal project, a small homelab setup that collected boiler and heating measurements into a PostgreSQL database. I was using AI to help me with some database migration work, restructuring tables and migrate them to a being partitioned. The AI gave me a sequence of SQL commands, confident and clear. I copied and pasted them into my database editor and ran them. No…

Services

Alongside my day job, I take on a small number of freelance projects — usually teams who need hands-on engineering help with Go, distributed systems, or cloud infrastructure. I'm selective about what I take on. I'd rather do a few things well than spread myself thin, so if your project isn't a good fit for my skills, I'll say so. What I can help with Backend engineering and…

Using CUE to unify IoT sensor data

I've been building a home automation system that processes motion sensor data from various IKEA Zigbee devices. Each sensor type sends a different data structure, and I needed to extract consistent information from all of them without sacrificing type safety. I spent a long time trying to make Home Assistant work for my setup. The visual automation builder felt limiting once I needed…

Building an MQTT client in Go

MQTT (Message Queuing Telemetry Transport) connects millions of IoT devices worldwide, from smart home sensors to industrial monitoring systems. Whilst many Go developers reach for existing libraries, building your own client wrapper teaches you the protocol's nuances and gives you precise control over connection handling, message routing, and error recovery. This article walks through…

Go 1.25's new JSON encoding package

⚠️ Important: The JSON v2 packages are experimental and their APIs may change in future releases. Use GOEXPERIMENT=jsonv2 to enable these features for testing. Go 1.25 arrived on 12th August 2025. This release included no language changes compared to recent versions. The most notable addition however was the inroduction of an experimental JSON implementation that improves encoding and decoding…

Go 1.24's new tool directive in go.mod

Go 1.24 introduces a fantastic new feature with the tool directive, simplifying how you manage project dependencies by integrating tools directly into your go.mod file. In distributed systems with numerous microservices, teams often prioritise consistency over progression, leading to tool version stagnation. The challenge of coordinating tool updates across a large estate of services frequently…

Building an HTTP server in Go with zero dependencies

Go 1.22 brought enhancements to the net/http package's router. Enabling method matching and wildcard patterns for HTTP routes. The standard library now provides a robust router that can handle most use cases, reducing the need for third-party routing libraries. Zero dependencies or minimal dependencies are a common requirement for many projects. In this post we will explore how we can…

Processing UK rail data in real-time

Info I've followed up this post with Consuming a real-time feed reliably , which generalises this pattern and addresses a few issues this version didn't handle well — notably idempotent batched writes and per-partition fan-out. Railway systems generate an endless stream of real-time data that needs to be captured, processed, and stored efficiently. When I was approached for a freelance…

Engineering arrogance

Innovation and rapid execution drive success in technology companies. When engineering teams collaborate effectively, they iterate quickly and maintain competitive advantages. However, arrogance within engineering teams can silently erode this foundation. Arrogance, ego and passive-aggressive attitudes within teams can stifle creativity, foster hostility, and hinder innovation. What is Engineering…

Building with the Google Sheets API in Go

Getting started with the Google Sheets API can be challenging for Go developers. From understanding A1 notation to managing batch operations. There are several concepts and patterns to understand. This guide walks you through building a robust integration with the Google Sheets API in Go. Setting Up Your Environment First things first. You'll need to set up your development environment by…

Building Stria to streamline payment data integrations

I've been working on a new side project. Stria , a service that will make payment data integration straightforward and reliable. As I get closer to launching I wanted to share a bit more about what I've been building and why. The Problem I'm Solving Every time I've needed payment data in the past in analytics tools or reporting systems. I've ended up building a custom…

PostgreSQL table partitioning with Go

PostgreSQL offers several ways to partition tables, including by range, list, or hash. There are various partitioning strategies available. This post will focus on a practical example using date-based partitioning from a recent project of mine. Demonstrating the concepts and implementation of table partitioning in practice. The Problem Let's start with a simple table that stores messages:…

YAML configuration: an unexpected bug

Few weeks ago I wrote about YAML configuration and why I believe they are the best of a bad bunch of formats. Within the post I talked abouit adding the ability for users to do string replacement with $LOG_LEVEL bash style variables. This worked great in situations where you had a variable on it's own e.g. l og : l evel : " $LOG_LEVEL " But I did not take into account secrets that may contain…

YAML configuration: the best of a bad bunch

Over the years, I’ve worked on a variety of systems, each with its own approach to configuration. From system.properties in Java apps to wp-config.php in WordPress, .ini and .toml files, JSON, and, of course, environment variables. None of these solutions are perfect. When dealing with application configuration you try to aim for a balance between: readability, maintainability, and flexibility.…

Deploying NixOS on Proxmox as an LXC container

I've been using NixOS for a while now, primarily to provision my personal and work Mac systems. While Nix can be complex and sometimes challenging to debug, I’ve enjoyed its unique approach to system configuration. However, I haven't explored much beyond that scope. For some time, I’ve become particularly interested in using it for containers, as NixOS offers compelling…

Why Go uses composition over inheritance

Recently, Andrew Cairns shared a post on Twitter/X featuring a shortened written version of his fantastic video, Composition over Inheritance Explained by Games . As I read through the article and watched the video again, I reflected on how, in Go, we don’t face the same concerns. Go's design philosophy emphasises simplicity, clarity, and efficiency, strongly favouring composition over…

Devlog 2 - Eventbus and SaaS model

It's been a while since I wrote a devlog. I aim to do these more regularly, but I got busy, sidetracked, and simply forgot. I kept reminding myself to get back to it but never did. In today’s devlog, I want to discuss the custom event bus I've written in Go to handle internal event delivery within my codebase. I have numerous events that need to trigger various actions, so this was a…

wip: wifi-qr Zig Rewrite

A couple of years ago, I frequently needed to join WiFi networks on external devices for testing. Entering long, randomly generated passwords multiple times per day became quite tedious. To address this, I created a simple bash script that queries the macOS Keychain to retrieve the current WiFi network's password and generates a QR code to simplify the process. The project can be found on my…

Devlog 1 - Foundations

Over the past few months, I've played around with multiple side projects. While working on these and the Stripe integrations, I realised I'd been through this process before—integrating Stripe, writing custom logic to handle Stripe Webhooks and building out features driven from the integration and wondered whether I had to repeat this each time. I decided to create a standalone…

yamlcfg: a Go library for YAML and environment variable config

Introducing yamlcfg , a new library designed to simplify YAML and Environment Variable configuration in Golang applications. I'm excited to introduce yamlcfg, a new library designed to simplify YAML and Environment Variable configuration in Golang applications This library utilises gopkg.in/yaml.v3 and the os.ExpandEnv function from Go’s standard library to replace any ${SOME_ENV_VAR} or…

Encrypting and decrypting with Go's crypto/aes and crypto/cipher

In an upcoming side project, I needed to encrypt and decrypt values stored in a SQLite database. This article offers an introductory overview of encryption and decryption practices but is not intended as a comprehensive guide. Encryption is a complex field that requires careful implementation to ensure data security. While searching for resources on this topic, I encountered inconsistencies and…

You probably don't need to mock

With the clickbait title out of the way, we can discuss why mocking may not be as crucial for Go testing as commonly perceived. Testing is vital to ensuring code reliability and functionality. However, the frequent use of mocks to replicate external dependencies can create a misleading sense of safety and test quality. While useful, mocks often fail to fully reflect the true complexity of system…

Continuous deployment with Go and GitHub Actions

The ability to deploy new features and fixes rapidly and reliably is a significant advantage. Continuous Deployment (CD) plays a crucial role in this context by automating the deployment process, ensuring that code changes are pushed to production or staging environments after successfully passing quality checks. This level of automation not only accelerates the development cycle but it also…

Deploying Docker images to Fly.io

Fly.io is a Platform as a Service (PaaS) enabling developers to deploy and run their applications globally, closer to their users. The Fly.io platform, notable for its simplicity and user-friendly design, has recently gained popularity. Fly.io transforms Docker containers into Firecracker VMs and strategically deploys them worldwide. There are a couple of different ways to build and deploy…

I suck at technical interviews

It's difficult for me to admit, but I struggle with technical interviews. I don't believe it's due to a lack of abilities or insufficient practice on platforms like LeetCode; rather, I think nerves and my dyslexia play a significant role. I tend not to highlight my dyslexia, as I've managed to overcome it in several areas over the years, and I'm concerned that disclosing…

Building your Go toolkit

After nearly 10 years of working with Go, including over 6 of those years as a full-time Go developer, I've come to rely on a set of tools and libraries that have significantly boosted my productivity. In this guide, I'll share the tools and libraries I use and discuss the importance of curating your own toolkit. Other developers have shared insights on building services and the…

Continuous integration with Go and GitHub Actions

Info Checkout my previous article on how to use private Go modules in local development and GitHub Actions workflows here . Info Checkout my latest post on how to Continuous Deployment with Go and GitHub Actions here . Introduction In a previous article , I explored how to use private Go modules in local development and GitHub Actions workflows. I did not cover how to use GitHub Actions to create…

Getting started with Go and Kafka using franz-go

Introduction In this Getting Started guide, we will explore integrating Golang with Apache Kafka. Kafka, is found in many distributed systems, as it excels in handling large-scale and real-time data streams. Its architecture, designed for high throughput and scalability, makes it indispensable in modern data processing pipelines. Golang, with its concise syntax and efficient concurrency…

Building a future-proof data pipeline with Go and Kafka

Introduction The device data processing system is an essential component for business operations. It was, however, becoming unfit for purpose as new systems and teams needed access to the data. The previous system had various limitations, was limited to one cloud platform and was restrictive in how consumers could access the data. We decided to incorporate a new architecture by developing a new…

Age: a practical guide to modern file encryption

age is a modern alternative to tools like to older file encryption tools like GPG. It is designed to be simple, modern and secure. age is built using modern encryption primitives and is designed to be easy to use. age works by creating or using public/private key pairs to encrypt and decrypt files. The public key can be shared with others to allow them to encrypt files that only you can…

Exploring Go 1.21: generics in the standard library and more

Exciting developments are on the horizon for the Go programming language as it enters the release candidate phase of its latest version Go 1.21. Among the most highly anticipated addition is the introduction of generics support to the standard library. This new release not only brings generics to the standard library but it also includes changes to the Golang's tooling, a new structured…

Using Go private modules with GitHub Actions

Info I've followed up this post with articles on Continuous Integration with Go and GitHub Actions and Continuous Deployment with Go and GitHub Actions . As the number of repositories within a project increases so does the complexity of the dependencies. As time goes on you begin to want to share code between the repositories. This is where Golangs Module system comes in handy. Creating new…

Understanding Go's sync.Cond

Exploring sync.Cond from the Golang sync Package After a colleague shared a video with me about the Go programming language reviewing the use of Go Generics and the Cond type from the go standard library sync package. The code being reviewed can be found on Github here . I decided to take a closer look at the usefulness of sync.Cond in managing synchronization in concurrent programs. Before…

The never-ending cycle of home DIY projects

There's nothing quite like starting a new DIY project, but it's not always as straightforward as you may think. There is always a constant worry that a new project may go wrong which could turn it into an even bigger project and uncover more underlying issues. It all starts straightforwardly enough. You have an idea for a new project, you dive headfirst into it, full steam ahead. But as…

Learning Rust

I previously wrote a blog post about rust back in June 2022 and I've still not really managed to spend a lot of time learning it. Busy personal and work life makes it difficult sometimes to focus on new projects and hobbies. But after a recently set of power outages I figured I needed a new dead man switch type alert system to notify me when my personal home server hasn't been in contact…

Just write

Robert Birming recently wrote an article named Just Write and it got me realising that to improve my own writing I need to "Just Write". I need to not care about who I am writing for, what I am writing for and why I am writing. I shouldn't care about my grammar, spelling and other mistakes that I make I think this is often a reason I use to not write and release blog posts. I get scared of…

The Rust programming language

While working with Golang often read about Rust as an alternative. Looking Rust is a low-level multi-paradigm, general-purpose statically-typed programming language designed for performance and safety. Rust makes it possible to write software that is safe and performant. One of Rust's biggest differences compared to other languages comes from the way it deals with objects and memory. Rust can…

Cleanup

Often end up finding I start to run out of space on my filesystem after a few months of use so I needed to find a way to search for directories that I know I can safely delete. For example for Node.js projects often end up with very large node_modules directory. The following command will list all node_modules from the current directory and there size. # List all directories named node_modules and…

Dot dev

Like many others, I recently rushed to get hold of one of the brand new dot dev domains waiting for them to become available via Google Domains . I didn't really have a plan for what I'd do with whatever domains I picked up but just knew I wanted aran.dev and aranw.dev . I've been using aranw as my go-to username for a few years now along with some others but I wanted to be the…

About

Hey, I'm Aran. I'm a software engineer based in Huddersfield, UK . I mostly work in Go, building backend services, data pipelines, and event-driven systems. I've spent a lot of time with Google Cloud (Cloud Run, BigQuery, Pub/Sub, Cloud Functions), PostgreSQL, and Kafka. Most of my work involves helping teams ship reliable systems that handle real traffic, whether that's…