Welcome to my blog

Sometimes, I feel the need to write, and this is a place where I can share what I write with others. I hope you find something interesting here. To learn more about me, you can visit the about page, or perhaps you want to take a look at my projects.

Deploying to BunnyCDN and protecting Norway from drop bears

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 enough to make pages load quickly across the other side of the globe. Seriously, the fastest thing in the universe cannot deliver cat pictures to people quickly enough. By using a CDN, you can geographically distribute assets like cat pictures, HTML, CSS, JavaScript, video files, fonts and much more. ...

April 20, 2025 · 8 min · 1609 words · Robin Kåveland

Checking SQL migrations with eugene

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 version was already good enough for me to start using in real projects — but it’s improved a lot since then, it’s now easy to run with almost no setup. ...

April 16, 2025 · 4 min · 658 words · Robin Kåveland

Running containers on no-ops linux in 2025

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

April 14, 2025 · 8 min · 1679 words · Robin Kåveland

Finding foreign keys missing indexes

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: create table author( id bigint generated always as identity primary key, name text not null ); create table book( id bigint generated always as identity primary key, author bigint not null references author(id), title text not null ); In this example, there’s a foreign key from the book table to the author table. Since author refers to a primary key in the author table, inserts into book can validate very quickly. There’s no index on the author column in the book table though. The consequence of this is that delete on author must check every single row in book to check if it’s safe to actually delete. The really annoying part of this is that the scan does not show up in query plans: ...

April 4, 2025 · 7 min · 1468 words · Robin Kåveland

Constraint propagation: Mutual recursion for fun and profit

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 problems, and we use it to make a solver for sudoku puzzles. Along the way, we explain the syntax we use, it shouldn’t be too hard to understand for someone who is unfamiliar with the language. ...

March 10, 2025 · 20 min · 4227 words · Robin Kåveland

Why would I use DuckDB for that?

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 not really for the same kinds of problems. I think DuckDB is primarily an analysis or ELT tool, and it really excels in this space. postgres can do a lot of the things that DuckDB can do, but not nearly as fast or easily. I wouldn’t want to use DuckDB for a transactional workload, so it’s not going to replace postgres for anything that I use it for. ...

March 2, 2025 · 13 min · 2570 words · Robin Kåveland

🎶 These points of data make a beautiful line 🎶

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 out that my headaches were probably due to my brain working overtime to interpret the world using mostly only one eye. My appointment with an optician was only a few days later, and I got to try a contact lens that same day. ...

January 31, 2025 · 7 min · 1376 words · Robin Kåveland

What if that isn't a bool?

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

January 8, 2025 · 4 min · 817 words · Robin Kåveland

Exploring a webapp using psql and pg_stat_statements

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 a ton of time to ingest technical text. ...

January 6, 2025 · 4 min · 688 words · Robin Kåveland

Consider using array operators over the SQL in operator

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

September 21, 2024 · 4 min · 674 words · Robin Kåveland