Posts - Robin's blog| Robin's blog
I have a small hobby project over at kollektivkart.arktekk.no that is for visualizing changes in public transit in Norway. For some time I’ve been wanting to do some visualizations on public transit lines. For example, plot the mean delay at each stop used by a line over time. When trying to do some concept work on this, I discovered a puzzle in the data! Many lines go in two opposite directions. Here in Trondheim, Line 3 goes from Loholt to Hallset, but also from Hallset to Loholt. The way...| Robin's blog
This post is part of the series on no-ops linux deployment. The first post covered local development of linux server configuration and essential configuration. The previous installment covers a janky podman installation and configures a reverse proxy to send traffic to a simple container deployment. This is the final post. It covers a more challenging deployment with jobs and rolling restarts, and discusses the strengths and weaknesses of this approach to hosting. After the previous post, we ...| Robin's blog
This post is part of the series on no-ops linux deployment. The previous post covered local development of linux server configuration and essential configuration. This installment covers a janky podman installation and configures a reverse proxy to send traffic to a simple container deployment. The final post covers a more challenging deployment with jobs and rolling restarts, and discusses the strengths and weaknesses of this approach to hosting. At the completion of the previous post, we ha...| Robin's blog
In Running containers on no-ops linux in 2025 I wrote about moving my hobby projects to a European cloud provider. I did an initial, manual setup in Hetzner, which I’ve now automated. This weekend, I tested the setup. It takes me a few minutes now to get everything moved to a new host, and most of that has to do with DNS. I’ve got a reproducible setup, I can quickly provision up a machine locally or in any cloud that has Ubuntu 24.04. Reproducible infrastructure is ✨liberating✨| Robin's blog
This is a note to myself about how to prioritize wisely. Or perhaps, it is an effort to commit to text a healthy mindset for myself. I have been trying to get into this mindset over a timeframe of some years now. I am making some progress, but it’s slow and not without setbacks. You can read it if you’d like, but this is my own advice for me. It may not apply to you.| Robin's blog
Working with SQL can sometimes be painful, especially when you have composite keys and many tables to join. Today I want to write a helpful tip for designing data models with such keys, to make it less painful to handwrite SQL for them. TIP: Introduce a consistent naming standard for all columns that take part in a primary key, so that the column has the same name in all tables it is used, also where it’s on the referencing side of a foreign key.| Robin's blog
When I was a kid, I thought adults knew everything there was to know. When I was a junior developer, I thought the senior developers knew everything there was to know about software. As anyone who has made some progression in life knows, nobody gives you the big manual with all the answers when you level up. You’ll still be you. Just with more responsibility and more experience. But the experience does not come from age, it comes from actually having to try. It’s okay to have no idea what...| Robin's blog
Not long ago, I wrote about running containers as part of moving my hobby projects to European cloud providers. That post was focused on running good old Linux servers. I briefly mentioned BunnyCDN but didn’t dive into the details. It’s time to dive into the details! What the flark is a CDN? A content delivery network is a geographically distributed network of servers that can deliver content to your users, close to where they are. It’s useful, because the speed of light isn’t fast en...| Robin's blog
It’s been almost a year since I last posted an update on eugene, the CLI tool I’m building to help people write safer SQL migration scripts for postgres. I announced this tool in Careful with That Lock, Eugene: Part 2. At the time, eugene would execute a single SQL script, recording all the locks acquired and warn about possible downtime due to migrations. It could produce JSON suitable for automated tooling and Markdown suitable for human reading and using in CI comments/checks. That ver...| Robin's blog
Back in February, I decided that I wanted to move hosting of my hobby projects to a european cloud provider. At this time, I don’t feel like spending more energy on why, but maybe someone can learn something from the how. I have pretty simple requirements, so I figured I should be able to find simple and inexpensive hosting too. It turns out that there are many european cloud providers in 2025, but none that were really a perfect fit for what I was looking for. Here’s what I wanted:| Robin's blog
Last week I was made aware that we had some foreign keys not backed by indexes in the system we’re developing at work. Foreign keys in postgres must be backed by an index only on the side they refer to, not necessarily the side they refer from. Here’s an example: createtableauthor(idbigintgeneratedalwaysasidentityprimarykey,nametextnotnull);createtablebook(idbigintgeneratedalwaysasidentityprimarykey,authorbigintnotnullreferencesauthor(id),titletextnotnull); In this example, there’s a fo...| Robin's blog
I’ve been wanting to write this post for a while, about what I think is an elegant way to solve some constraint satisfaction problems. Constraints tend to come up fairly often in real world programs, and some times it can be effective to treat them as constraint satisfaction problems. This post has a bit of background on constraint satisfaction problems I’ve encountered recently, then it goes over to develop Rust code for an algorithm that we can easily use to solve some Advent of Code pr...| Robin's blog
The past few weeks I’ve been experimenting with DuckDB, and as a consequence I’ve ended up talking about it a lot as well. I’m not going to lie, I really like it! However, experienced programmers will rightly be skeptical to add new technology that overlaps with something that already works great. So why not just use postgres? Well, I really like postgres too, and I think you should consider just using it! But despite both of these technologies being all about tabular data, they’re no...| Robin's blog
One of my most vivid memories is from the day in my late teens when I first got a contact lens for my left eye. It took a long time to discover that I had poor vision on this eye, you see, like many people, I chose to keep both of my eyes open when I wasn’t sleeping. It was the headaches that sent me to a doctor. I was adamant that I could see well, but when he blocked my right eye, I had the humbling experience of no longer being able to read the biggest letters on the poster. It turned ou...| Robin's blog
A common way that code grows difficult to reason about is increasing the number of things you must keep in your head simultaneously to understand it. Often, this simply happens by adding one attribute, one variable, one column at a time. Some people are gifted with a great capacity for working memory, but most of us aren’t – having to hold the state of 5 variables in your head simultaneously to understand a piece of code may be pushing it far, according to this article from wikipedia:| Robin's blog
It’s always an exciting day for me when I get access to the source code for an entirely new application I need to work on. How does it look inside, how does it work? Sometimes, there’s some design documentation along with it, or operational procedures, or maybe some developer handbook in a wiki. I do check all of those, but I don’t expect any of those things to accurately describe how the code works, because they tend to change less frequently. It’s also fairly low-bandwidth, it takes...| Robin's blog
In my post about batch operations, I used the where id = any(:ids) pattern, with ids bound to a JDBC array. I’ve gotten questions about that afterwards, asking why I do it like that, instead of using in (:id1, :id2, ...). Many libraries can take care of the dynamic SQL generation for you, so often you can just write in (:ids), just like the array example. I would still prefer to use the = any(:ids) pattern, and I decided to write down my reasoning here.| Robin's blog
Throughout a career as a software developer, you encounter many patterns. Some appear just often enough to remember that they exist, but you still need to look them up every time. I’ve discovered that writing things down helps me remember them more easily. This particular pattern is very useful for my current project. So, it’s time to write it down and hopefully commit it to memory properly this time. Although this post is specific to PostgreSQL, I’m sure other databases have the necess...| Robin's blog
For this blog post, I’m trying something different. This is a jupyter notebook that I’m using to study some data, and just dumping my brain out in text. If I can easily export this to a format that works with hugo, this might become a common occurrence. For this one, I’m leaving the code in. There isn’t that much of it, but I think it’s fun to show how much visualization per line of code you can get with seaborn and pandas.| Robin's blog
Database servers are usually long-lived, and important parts of the infrastructure that we build on. We rarely set them up from scratch, because we have to take such good care of them over time. I think this causes a lot of people to think that setting up a database server is some mysteriously difficult ordeal. To be clear, that’s actually true, if you need high availability and a solid recovery point objective. But there are a lot of use cases where that’s overkill, for example short-liv...| Robin's blog
I’ve been busy working on a documentation site for eugene, and I think it’s starting to look pretty good. I wanted to write down some of my thoughts around the process so far, and some of the things I’ve learned. It’s just been a few days since I ported my blog to hugo, so since I was already feeling like I was up to speed on that, I decided I’d try using it for the eugene documentation too. I experimented with a few different setups around the hugo-book theme, but it ended up feeli...| Robin's blog
I’ve been using pelican for my blog for a while now, and I don’t really have anything negative to say about it. But for a while, I’ve been wanting a more minimal theme. I ended up on the front page of hacker news a couple of times, and the old theme had my face on all the pages, which made me feel a bit uncomfortable. I was looking at some other themes around the web, and I found PaperMod which I absolutely loved. I followed instructions for how to set it up, and it turns out that it on...| Robin's blog
I have been working quite a bit on picking up dangerous migration patterns in migration scripts over at the eugene repository lately. A major feature I’ve added is syntax tree analysis, so that we can pick up some patterns without having to run the SQL scripts. This isn’t quite as precise as running the scripts, but it’s a lot faster and can catch quite a few common mistakes. So let’s take a look at how it works!| Robin's blog
In my current project, we’re working on a large-ish code base that is written in Scala and uses cats effect as an effect system in large parts of the code base. If you’re not familiar with what an effect system is, I think the most important detail is that it’s a tool that gives you certain superpowers if you promise to be honest about it when your code does things that can be considered “effectful”, such as interacting with the network or reading files. We use the IO monad from cat...| Robin's blog
A while back, I wrote Careful with That Lock, Eugene about an idea for how to check if a database migration is likely to disturb production. That post came about after having an inspiring chat with a colleague about the advantages of transactional migration scripts and the ability to check the postgres system catalog views before committing a transaction. Over the past few weeks, I’ve been experimenting with this idea to test if I can use it to build valuable safety checks for DDL migration...| Robin's blog
I have a few projects on my GitHub that I sometimes work on: eugene is a postgres SQL migration checker, sort of like shellcheck but for database migration scripts. It can parse SQL, or trace the effects of the scripts in a database and report about things that could lead to outages in production. It has a fancy documentation site here. pyarrowfs-adlgen2 is a connector between Apache Arrow and Azure Data Lake Gen2. It’s good for reading and writing files in storage accounts with hierarchial...| Robin's blog
It is rewarding to work on software that people care about and use all around the clock. This constant usage means we can’t simply take the system offline for maintenance without upsetting users. Therefore, techniques that allow us to update the software seamlessly without downtime or compromising service quality are incredibly valuable. Most projects I’ve worked on use a relational database for persistence, and have some sort of migration tool like flyway or liquibase to make changes to ...| Robin's blog
If you’re developing a transactional application backed by postgres, there’s a pretty cool trick you can use to check if you’re missing indexes that could potentially cause serious performance issues or even outages. In particular, I mean foreign keys where the referencing side of the constraint does not have an index. The idea is very simple, we can select all of the columns that take part in a foreign key, then remove the ones that take part in a complete index, and the remainder shou...| Robin's blog
I worked for a few years in the intersection between data science and software engineering. On the whole, it was a really enjoyable time and I’d like to have the chance to do so again at some point. One of the least enjoyable experiences from that time was to deal with big CSV exports. Unfortunately, this file format is still very common in the data science space. It is easy to understand why – it seems to be ubiquitous, present everywhere, it’s human-readable, it’s less verbose than ...| Robin's blog
For tests that need to touch the database, it is generally a really good idea to roll back transactions. That way, you can run lots of tests in parallell or in any arbitrary order and the tests won’t interfere with each other. But sometimes, that just isn’t possible. One reason for this could be that the code base handles transactions in a way that makes it really hard to get a handle on them in the right place, or it could be a legacy code base where everything is running with auto-commi...| Robin's blog
I am Robin and this blog is a place where I can write about things I find interesting. I’m an experienced software engineer, living in Trondheim, Norway. I work as a consultant for Arktekk. There are lots of topics related to my work that I’d like to write about: Things I learn. In my line of work, I learn something new almost every day, and I’d like to get better at writing down some of those things. Debugging and tools for debugging complex systems. I love a good debugging story and w...| Robin's blog
There are 2 configuration options that every OLTP application that uses postgres should set, in order to protect the database from high load: statement_timeout idle_in_transaction_session_timeout These can both be set by client configuration and require no special permissions to set, and are easily overridden locally for transactions that have different requirements. They can be a bit scary to retrofit to existing applications, but we can activate two postgres extensions to help us measure ou...| Robin's blog
Welcome to my blog| Robin's blog
Imagine entering the biggest library in the world. You peer down an incredibly long aisle with wooden bookshelves brimming with books. You can see multiple such corridors, all lit with a comfortable warm light. There’s a rich smell of old paper. You can hear some muted voices, perhaps arguing in a whisper. It’s perfect, but vast and difficult to make sense of. Just this day, it doesn’t feel like such a terrible ordeal to just wander for a while, see where your legs take you. Maybe you...| Robin's blog