What I think about...
I enjoyed blogging until around 2020, but these days I no longer have the time for it. Since I use AI to learn about new technologies, algorithms and other dev topics, I pipe the interesting results into this blog. AI-generated posts are marked. I use Claude and Gemma. Translations are AI-generated as well.
The Trigram Algorithm: Fuzzy Matching Without the Magic
A trigram is just three consecutive characters, and comparing the sets of trigrams of two strings gives you a fast, typo-tolerant similarity score between 0 and 1. It is the ide…
Building a Custom Data-Fetching Hook in React
Every React codebase eventually accumulates a dozen near-identical blocks that fetch data, track loading state, and handle errors. Extracting that pattern into a single reusable…
CSS Container Queries: A Practical Guide
Media queries answer one question: how big is the viewport? That's the wrong question for most components, because a card, a sidebar widget, or a product tile doesn't care how w…
How the Virtual DOM Actually Works
"The virtual DOM makes React fast" is one of those phrases everyone repeats without quite being able to explain. It's not magic, and it's not even always faster than touching th…
Understanding Web Workers for Heavy Computation
JavaScript runs on a single thread, which means a computation-heavy task — parsing a huge JSON blob, resizing an image, running a pathfinding algorithm — blocks everything else…
Debouncing and Throttling: Taming High-Frequency Events in JavaScript
Every frontend developer eventually hits the same wall: a scroll handler firing hundreds of times a second, a search input triggering a network request on every keystroke, or a…
Writing a Simple Command-Line Tool in Node.js
Most internal CLI tools don't need a framework. A script that renames a batch of files, hits an internal API, or wraps a repetitive sequence can be a single Node file with a she…
Web Accessibility Basics: ARIA Without the Guesswork
The most common ARIA mistake isn't using the wrong attribute — it's reaching for ARIA at all when a native HTML element would have solved the problem for free. ARIA (Accessible…
A Practical Guide to Git Branching Strategies
Most teams don't choose a branching strategy — they inherit whatever the founding engineers happened to do, and it calcifies before anyone questions whether it fits the team's a…
Building a Simple State Machine in TypeScript
If you've ever written a component with , , , and as separate booleans, you've probably also shipped a bug where two of them were true at the same time and the UI showed a spinn…
Reflows and Repaints: Why Your Page Feels Janky
You measure an element's height with , use it to set another element's width, read that width back, and set a third element's height — and somehow this fifteen-line function is…
Understanding HTTP Caching Headers
Most performance problems people try to solve with a CDN or a caching layer are actually solved for free by three HTTP headers, set correctly, that most apps get wrong by accide…
A Practical Guide to API Pagination
Return every row from a growing table in a single response and you've built a feature that works fine in development and falls over in production the day a customer has 50,000 r…
Understanding Database Connection Pooling
Opening a database connection is expensive: a TCP handshake, authentication, sometimes TLS negotiation — commonly tens of milliseconds before a single query runs. Open one conne…
Writing Your First GitHub Action
Most teams start with GitHub Actions by copy-pasting a workflow from another repo and hoping it still applies. That works until the day it doesn't, and you need to actually unde…
Understanding the JavaScript Event Loop
JavaScript runs on a single thread, yet somehow handles thousands of concurrent network requests, timers, and UI events without blocking. The event loop is the mechanism that ma…
Debugging Memory Leaks in Node.js
A Node process that slowly climbs in memory usage over hours or days, then eventually gets OOM-killed by the container orchestrator, is one of the more frustrating classes of bu…
A Practical Guide to Semantic Versioning
in a looks precise, but that caret changes what it means depending on whether the maintainer on the other end actually followed the rules it's built on. Semantic Versioning (sem…
Big O Notation, Explained with Real Code
Big O notation gets taught with abstract examples — sorting arrays of integers, searching balanced trees — and then quietly dropped once people start shipping actual features. T…
Feature Toggling with Environment-Based Config
The simplest way to ship a half-finished feature to production without exposing it is also the most commonly reinvented badly: a boolean, read from config, checked in an . Befor…
Building a Rate Limiter Middleware in Express
An unprotected API endpoint is an invitation: one misbehaving client script, one retry loop without backoff, one scraper, and your server spends all its time serving the same ha…
Understanding Content Security Policy (CSP)
Content Security Policy is a browser feature that limits where a page is allowed to load scripts, styles, images, and other resources from — and it's one of the few defenses tha…
Building a Simple Job Queue with Redis
Sending a welcome email, resizing an uploaded image, generating a PDF report — none of these should happen inside the HTTP request that triggered them. A job queue lets you hand…
The Repository Pattern: Pros, Cons, and When to Skip It
The repository pattern gets recommended by default in a lot of backend tutorials, right alongside dependency injection, as if skipping it were obviously wrong. It isn't. It's a…
Database Transactions and Isolation Levels Explained
"Just wrap it in a transaction" is common advice, but a transaction alone doesn't guarantee two concurrent operations won't step on each other — that depends on the isolation le…
Retry Strategies: Exponential Backoff and Jitter
A network call fails. The obvious fix is "just retry it" — but retrying naively is how a brief blip turns into a full outage, because every client hammers the recovering service…
A Gentle Introduction to WebSockets
HTTP is request-response: the client asks, the server answers, the connection's job is done. That model breaks down the moment the server needs to tell the client something with…
Async Iterators and Generators in JavaScript
loops over arrays and other iterables one value at a time. does the same thing when each value takes time to produce — reading paginated API results, streaming a large file, or…
Memoization in JavaScript, Beyond useMemo
Memoization caches the result of a function call keyed by its arguments, so calling it again with the same arguments returns the cached value instead of redoing the work. Most J…
Building a Simple Pub/Sub System in Node.js
Publish/subscribe decouples the code that produces an event from the code that reacts to it — the publisher doesn't know or care who's listening, and subscribers don't know or c…
The CAP Theorem, Explained with Real Examples
Every distributed database vendor claims to be fast, consistent, and always available. The CAP theorem is the reason you should be suspicious of that pitch: in the presence of a…
A Practical Guide to JWT Authentication
JSON Web Tokens get reached for by default in a lot of new backends, often without anyone stopping to check whether a token is actually the right fit, or what happens the day yo…
Event Sourcing vs Traditional CRUD
A traditional CRUD table tells you the current state of a row and nothing about how it got there. Event sourcing inverts that: it stores every change that ever happened, and cur…
Structured Logging: Why printf Debugging Doesn't Scale
works fine until you have ten servers, a thousand log lines a second, and an incident where you need to find every request from one customer across three services in the last tw…
Understanding CORS Once and For All
CORS errors show up in the console at the worst possible time, say almost nothing useful about how to fix them, and get "solved" by copy-pasting from Stack Overflow without anyo…
Rate Limiting Algorithms: Token Bucket vs Sliding Window
Every public API eventually needs rate limiting, and the algorithm you pick decides whether "100 requests per minute" actually means what it sounds like. Two approaches dominate…
The N+1 Query Problem and How to Avoid It
A page that lists 50 blog posts along with each author's name feels instant in development, with a handful of test rows, and then falls over in production the moment real data s…
Git Rebase vs Merge: When to Use Which
and both get your feature branch's changes onto , and that surface-level similarity is exactly why people mix them up and end up with either a tangled history or a rewritten one…
Writing Safe, Idempotent Database Migrations
A migration that ran successfully in staging and then fails halfway through in production leaves you in the worst possible spot: a schema that's neither the old version nor the…
How Database Indexes Actually Work
"Just add an index" is the most common piece of database advice, and also the most commonly misapplied — thrown at slow queries without understanding what the index actually doe…
Optimistic vs Pessimistic Locking in Databases
Two requests read the same row, both compute a new value from what they read, and both write it back — the second write silently overwrites the first as if it never happened. Th…
The Circuit Breaker Pattern for Resilient Services
When a downstream service starts failing, the naive response — keep retrying every request as it comes in — is exactly the wrong move. Every retry is another request piling onto…
Feature Flags: A Practical Guide
A feature flag is a conditional wrapped around a piece of code that lets you turn that code on or off — for everyone, for a subset of users, or gradually — without shipping a ne…
Understanding TypeScript Generics
Generics are the feature that trips people up right after they've gotten comfortable with basic TypeScript types — and then, once it clicks, becomes one of the most-used tools i…
Building an LRU Cache From Scratch
An LRU (least-recently-used) cache keeps a fixed number of items and, when it's full and a new item needs to be added, evicts whichever item hasn't been touched in the longest t…
Idempotency Keys in REST APIs
A client sends a payment request, the network times out before the response comes back, and the client — reasonably — retries. If your endpoint just runs the charge again, the c…
Python3 - Renaming Files With the Same Name
If you want to quickly and conveniently move/copy your files from a case-sensitive file system to a file system that is not case-sensitive, you can use this script to quickly re…
Mail Management / Spam Protection
I hate SPAM. You can probably tell from the number of blog posts (you could almost think the whole blog is only about spam). By now, though, I've found a relatively perfect way…
The Importance of Accessible Web Design: A Gateway to Inclusivity and Usability
In a world increasingly shaped by digital technologies, the accessibility of websites and applications for all users is of crucial importance. Accessible web design goes beyond…
The Invisible Threat: XSRF - When the Web Works Against You
In a world where our personal information and online activities matter more and more, security in cyberspace is of crucial importance. One threat that often lurks in the shadows…
Detecting Brute-Force Attacks
During a Saturday stay at a coffee house, and after my provider OVH informed me that a DDoS attack was currently hitting my vServer, I gave some thought to how one could detect…
React Native - What?
Before we really get started, let me tell you a joke first: do you know why developers love working with React Native so much? Because they can kill two birds with one stone: th…
JavaScript - The THIS Keyword
In the world of web development, JavaScript is one of the most widely used programming languages. Despite its popularity, though, there are a few tricky concepts developers can…
Dependency Injection
In the world of software development there are many concepts that are essential for building robust, scalable and easily maintainable applications. One of them, which has grown…
The Power of Method Chaining in C#: A Guide to Efficient Code
In the world of software development, efficiency is a key concept. Efficient code isn't only easier to read and maintain, it also helps increase productivity and improve softwar…
Scriptable: Checking Your Contact Lens Status
A small Scriptable widget for tracking the current status of your contact lenses and lens case. Since I keep forgetting to change my contact lenses after 30-40 days (or, alterna…
Marlin Firmware: SKR Mini e3 v3
Maybe some of you would like to save yourselves the trouble of compiling and configuring the Marlin bugfix version 2.1.X for the Creality Ender 5 on your own. Configuring the CR…
Autosort: Sort Photos and Videos Quickly and Easily
This is the successor to the script presented here: GoPro & Photos: Automatically Rename and Copy
Promises
A concept that many developers find hard to understand at first: promises.
JavaScript - Generators
JavaScript generators are a powerful function technique available to JavaScript developers. Generators let developers write asynchronous functions in a cleaner, more structured…
JavaScript - Closures
A closure is created when a function accesses a variable or function outside its own scope. Essentially, a closure is a function that remembers the values that were available in…
Automatically Rename and Copy GoPro Photos
There is a newer and better version here: Autosort - Sort Photos and Videos Quickly and Easily
C# Delegates
A delegate is a kind of pointer to a method or a group of methods that can be called without you having to know details about the underlying implementations. Delegates are espec…
Auto-Backup to Amazon S3
Lately I've become very critical about the safety of my backups. Especially since I experiment quite a lot with my vServer (which, among other things, hosts this website) and oc…
Udemy Auto-Enroll Script for Tampermonkey
On myDealz there are regularly threads listing free Udemy courses. Once you've enrolled in a course, you can watch it at any time, as long as it stays online.
JavaScript Object Notation with SQL
Databases are wonderful for storing structured data. Sometimes, though, for various reasons that isn't enough, and you'd rather store more complex data structures via SQL. For e…
The Null-Conditional Operator
The "null-conditional operator" is a feature introduced with C 6.0 that lets developers handle null values more safely. It is a simple operator that acts as an optional member a…
Validating Email Addresses
One commonly used method (admittedly by me too) to protect yourself from email spam is simply not to enter a valid email address when registering. I have signed up as sapdojapjd…
Returning MySQL NULL as 0
For a small project I had to sum the values of a column in MySQL and sort by the summed values. Something like
AlphaGo
If you're interested in AI and want an easy-to-digest, almost "feature film" style take on the topic, you should definitely watch the documentary about the AlphaGo match. Absolu…
Simultaneous Chess
As a big chess fan, I'm of course a subscriber of GM Huschenbeth. I found his 40k special exciting, in which he plays simultaneously against several subscribers. Unfortunately h…
NASA - Visualizing Elevation Data
A small snippet for visualizing NASA elevation data. You can get the data here: https://lpdaac.usgs.gov/products/srtmgl3v003/
Youtube-DL Download MP3 (fast!)
For some time now I've been using the wonderful tool youtube-dl. If you don't know it: it lets you download videos, music and more from many sites. Its feature set is broad, but…
Brute Force Protection
Brute-force attacks on web applications are a serious problem, especially for larger websites with many users. An attacker tries to compromise a user account either with random…
Brand-New MacBook Just Shuts Itself Off
A little story about Apple, or the worst and most frustrating purchase experience I've ever had. Maybe it helps one or the other user. I've split the incident into "The full sto…
Autopush - Simply Upload Changed Files
To simplify my web design / web development workflow, I wrote myself a small autopush script. The script watches a given folder and all its subfolders for changes and uploads th…
CentOS - Server Essentials
Every now and then I have to set up my CentOS server from scratch (either because something went wrong again or because I miss the satisfying feeling of a new, clean system), an…
Fire on enter
A small JavaScript/jQuery snippet that triggers an action as soon as the Enter key is pressed in a field.
\"This copy of the Install OS X Sierra application can't be verified\"
Today I wanted to hand my old Mac over to a friend, and as a conscientious user I of course reset everything to zero first. So I quickly created a bootable USB stick via
Simple Image Resizing + Caching
Every now and then an existing image is needed in a different size. You can either use Photoshop to create an individually cropped version of the image for each case and embed t…
Simple Template Engine
For a somewhat larger project I was looking for a simple template engine. I didn't want to write the same code over and over for both my server-side and client-side scripts, whi…
Converting Seconds to Days, Hours, Minutes and Seconds
In a project I was working on this morning, I had a bit of a headache converting a number of seconds into days, hours, minutes and seconds. It's actually simple, but I was stuck…
Time Machine -5058
Worst case scenario: the backup goes haywire. Normally I back up IT projects twice. My cron job runs automatically every day at 24:00 and creates a local backup of my localhost,…
Scrollblur
As a "design freak" I'm always looking for suitable inspiration, and what better way than to drop by the websites of the big agencies every now and then; that's how I occasional…
Javascript Snippets
Here I collect a few JavaScript snippets. A list that will surely grow over time :)
Bash Snippets
A few useful (or pointless) Bash snippets that come in handy every now and then. Have fun with them.
Don't Trust a Scan You Didn't Forge Yourself
A really interesting talk that shows a (rather amusing, dramatic) bug in Xerox copiers. In short: Xerox copiers cache similar image patches and then reuse them over and over whe…
SPAM protection methods N° 2: Timing is everything
As part of the "SPAM protection methods" series, we continue with part 2 and the ominous title "Timing is everything". It's based on the consideration that users filling out a w…
SPAM protection methods N° 3: Timing is once again everything
Page navigation, too, lets us exploit the speed difference between a bot and a real user quite well. While a user normally stays on a page for a few seconds until they've taken…
Handling HTTP Range Requests with PHP
Sometimes we don't want to load the entire file from the server, but only a certain section (range) of it. So we want to define a start byte and an end byte and return all data…
SPAM protection methods N° 1: Honeypot
A tiresome topic since the dawn of the internet is SPAM (no, not the canned meat, that has been around longer than the internet). On a bored weekend I gave some thought to how w…
Javascript Promises
Since June 2015, promises have arrived in JavaScript with ES6 and can be used natively. Maybe some of you are like me at the beginning and don't quite know what promises are goo…
Avoiding SPAM with qmail
SPAM. Everybody hates it, nobody can (seriously) avoid it. To keep the inbox reasonably tidy, though, there's a rather convenient solution: temporary email addresses! temp-mail.…
PHP Snippets
Sometimes you need to swap two variables quickly, and at some point I wondered whether that's possible without a temp variable. Since then this has been my best practice:
OpenGeoDB Hurdles
For a current project I needed a list of all postal codes in Germany including the associated city names. "The more data the better" applies, of course ;-) but these were at lea…