RSSAmplifier

Blog

Martin Hicks - Journal

Martin Hicks is a software developer from Manchester, UK

martinhicks.devRSS feed ↗34 posts

Latest posts

Parity Suite 3.0.0: measuring the wrong thing

Since the board started it has published one number per emulator: a pass rate over the tests that emulator attempted. Skipped tests left the sum entirely. Which means the number could move without the engine changing a line. In July one emulator gained 8.4 points having shipped nothing at all. 3.0.0 replaces that number. Two figures instead of one, a letter grade on every target, and the suite is…

When a DynamoDB vector index is actually ready

AWS shipped vector search for DynamoDB on 5th August, straight to GA. I spent a couple of days pinning it down against real DynamoDB so I could add it to my conformance suite , which meant reading the docs properly and then checking whether they were true. Mostly they are. But there's one thing they get wrong three different ways, and the three stack up: knowing when a vector index is ready to…

What a write to an indexed DynamoDB table costs

My conformance suite has had a per-index capacity assertion since fairly early on. It was on a Query . Which is the wrong half. Reading through an index is the cheap, obvious, well-understood part. The write side is where a secondary index actually costs you money, because every write to the base table fans out to every index the item lands in, and you pay for each one. That went unmeasured for…

Dynoxide 0.12.0: PartiQL RETURNING, wasm conformance

Dynoxide 0.12.0 is out. PartiQL now honours RETURNING , and the browser build has been through the conformance suite for the first time. There's a stack of smaller fixes below, and one breaking change if you build against the Rust crate. PartiQL RETURNING Dynoxide has been parsing the RETURNING clause since PartiQL landed, and then dropping it on the floor. DELETE FROM Music WHERE artist =…

You can't pin DynamoDB to one region

A conformance suite is only as good as its ground truth. Mine works by running every test against real DynamoDB and recording what comes back, so the expected answer is never my reading of the docs - it's what the service actually did when I asked it. That only holds up if real DynamoDB does the same thing everywhere. It mostly does. Not always. Take PutItem with an attribute value of { NULL:…

Dynoxide 0.11.3: closing a Windows port hijack

Dynoxide 0.11.3 is a small one, and for once there isn't a conformance fix in it. It's about who is allowed to bind the ports. An issue had been sitting on the tracker for a while: investigate SO_EXCLUSIVEADDRUSE on Windows, for parity with the TIME_WAIT bypass dynoxide already had on Unix. I finally picked it up this week, and the investigation came back inside out. The parity already existed.…

Dynoxide 0.11.2: a stack of conformance fixes

Dynoxide 0.11.2 is a conformance patch - a stack of fixes for spots where the engine did something real DynamoDB doesn't. Most of it is drift the conformance suite turned up faster than I'd been closing it. The lead one I can tie to something concrete: last week I worked out what a conditional DynamoDB transaction costs and pinned the numbers against real AWS. This release makes dynoxide report…

What a conditional DynamoDB transaction actually costs

Leonie opened an issue on the suite the other week with a question I couldn't answer off the top of my head: when you run a conditional write inside a DynamoDB transaction, does the condition cost you read capacity on top of the write? Or is it write capacity all the way down? So I went to the docs. They were... not clear. There's a line on the transaction API page about idempotent retries…

Dynoxide 0.11.1: four conformance fixes

Dynoxide 0.11.1 is a small patch. Four fixes, all the same shape: spots where the engine evaluated a condition expression or validated a number slightly differently from real DynamoDB. No new features - just drift the conformance suite turned up, most of it checked back against real AWS before I closed it. Map and list equality in a ConditionExpression . Comparing an M or L attribute with = always…

Learn DynamoDB by running it - accesspatterns.dev

I've been building on DynamoDB since around 2015, and these days I build tools for it: dynoxide , a DynamoDB engine, and Nubo , a native client. So I'm not neutral about it. It's the first database I reach for, and with reason - the operational overhead is close to nil, no connections to pool or instances to size, and it holds the same single-digit-millisecond reads whether the table has a…

Dynoxide 0.11.0: wasm on npm, plus a stack of fixes

Dynoxide 0.11.0 packages the browser engine as an npm module and fixes a stack of correctness bugs. Last release got the engine running in the browser, but you had to wire up the Web Worker yourself to use it. Now there's a package that does that for you . The fixes are mostly small things the conformance suite turned up - nothing dramatic, but the sort of drift you want closed if you're going to…

I watched DynamoDB change under my conformance suite

My DynamoDB conformance suite went red this week, and the test that failed was real AWS. That needs explaining. The suite runs a few hundred tests against real DynamoDB first, records exactly what the real thing does, then runs the same tests against the emulators people reach for locally - DynamoDB Local, LocalStack, Dynalite, my own engine - and scores how closely each one matches. Real DynamoDB…

Build the squad. Own the platform. The org chart will catch up.

My wife Helen, who works in HR, sent me an episode of HR Disrupted last week - Lucy Adams interviewing Andy Doyle from Kantar on putting AI agents into production HR workflows. Andy describes some genuinely impressive work. Kantar had around 4,000 HR policies spread across 63 markets. Twenty-three versions of a single policy were scattered across the intranet, many written by different people at…

Dynoxide 0.10.0: it runs in the browser now

A DynamoDB-compatible database, running in a browser tab. No server, no network. The data lives in the origin private file system , and the query engine is the same Rust that backs the native build, compiled to WebAssembly. That's the thing I'm most pleased about in dynoxide 0.10.0. It's a big release, and the first one that isn't a clean upgrade. So here's what shipped, why, and what bites you on…

Running iai-callgrind on Apple Silicon

My instruction-count benchmarks for Dynoxide , my embeddable DynamoDB engine in Rust, only ever ran in CI. The wall-clock benchmarks ran happily on my Mac, but the iai-callgrind track ( benchmarks/benches/iai_core.rs ) just sat there - because it needs Valgrind, and Valgrind doesn't run on Apple Silicon. Not "runs badly", not "needs a flag" - there's no aarch64 Darwin port at all. So on the…

How close is your DynamoDB emulator to AWS?

My DynamoDB conformance suite has a site now: paritysuite.org . Eight emulators, 684 tests, scored against live AWS DynamoDB. The README only ever showed a single snapshot, frozen at whenever I last updated the table. The site shows everything around that snapshot. The homepage is the standings - every target ranked by how closely it matches real DynamoDB, with DynamoDB itself pinned at the top on…

Filing my first security advisory

Yesterday I logged into GitHub and noticed a Dependabot alert sitting on dynoxide. DNS rebinding CVE in rmcp , a transitive dependency. The alert had been raised a few days earlier - I just hadn't seen it, because I'd never set up email notifications for Dependabot on that repo. First lesson of the day, before the actual lesson of the day. I worked through the fix and published a GitHub Security…

Dynoxide patch notes: 0.9.10 to 0.9.12

Dynoxide now lives entirely in its own public repo , out of the private workspace it shared with Nubo . One repo, one CI pipeline, no shuttling private commits to test against the public version. That's the work behind 0.9.10 that doesn't show up in the changelog. Three patch releases since. 0.9.10: making error messages actually match v0.9.10 closed 16 places where dynoxide's error strings…

A year with my Intel N100 home server: what changed

It's been a year since I built my Intel N100 home server , and a few things have happened since I wrote that post. Some of what I set up is still humming along untouched. Some of it I quietly tore out. And some of what I added wasn't on the original plan at all. This is the honest "what I'd actually do differently" follow-up. The boring infrastructure won The most useful thing I can report is how…

Building a DynamoDB conformance suite

Update, July 2026. Since I wrote this, the DynamoDB conformance suite has grown from the 526 tests below to 954, and it now has a name and a board of its own: Parity Suite. The current standings are live at the DynamoDB conformance board . The rest of the article is left as it was, a record of where the suite started. When I started building Dynoxide - a DynamoDB-compatible engine in Rust - I kept…

Dynoxide 0.9.8: fixing the orphan problem

Dynoxide 0.9.8 fixes a bug where backgrounding dynoxide in an npm script left it running after the parent process exited. The port stayed bound, and the next npm run dev failed with a port conflict. There were three separate causes. The Rust server ignored SIGTERM kill <pid> sends SIGTERM by default, but Dynoxide only handled SIGINT (Ctrl+C). The fix is a tokio::select! between ctrl_c() and a…

Introducing Dynoxide: a fast, embeddable DynamoDB engine

I've been working with DynamoDB for the best part of a decade. It's my default database for most things I build at Si Novi , and I genuinely like it. The data modelling is satisfying once it clicks, the operational overhead is basically zero, and it scales without you having to think about it. Last year, Si Novi started building Nubo , a native DynamoDB client for macOS and iPadOS, with Windows…

Automating my son&#39;s YouTube with Python and FFmpeg

My son Ben is 12. Back in August he decided he wanted to start a YouTube channel. We talked about what it could be and he landed on Premier League score predictions. Every gameweek he'd predict the scores for all 10 matches, record himself talking through his picks, then after the weekend we'd see how he did and record a review. Simple concept. He was into it. I was into it. Let's go. The manual…

Recently Played: bringing back my Last.fm component

Around 2010, my personal website had a Last.fm widget showing what I'd been listening to. It was a small thing - just a few album covers and track names in the sidebar - but it was very me . Back then your personal site was an extension of yourself, and having your music taste ticking away in the corner felt right. Fast forward fifteen years and I've rebuilt this site from scratch several times…

WireGuard for safe browsing on kids&#39; devices

After setting up AdGuard Home and Unbound on my home server , DNS filtering was working perfectly for every device on the home network. But children's devices don't stay on the home network. They go to school, to friends' houses, connect to public Wi-Fi, and use mobile data. In all of those situations, the home DNS filtering was being bypassed entirely. The solution was WireGuard VPN , configured…

Running AdGuard Home and Unbound on a home server

After building my Intel N100 home server , the next step was improving the network itself. The server was sitting there running 24/7, barely using any resources. Perfect for handling DNS. My goals were straightforward: Block ads and tracking across every device on the network Block malicious and adult content domains Stop relying on third-party DNS resolvers for privacy Get better visibility into…

Building a tiny Intel N100 home server

Over the past few years my home setup has gradually grown more complicated. Between family devices, work machines, backups, development tools and general tinkering, I'd slowly accumulated a mixture of cloud services, routers and older hardware doing different jobs. None of it was joined up, and none of it was particularly efficient. I wanted a single small home server that could handle a few key…

Remove trailing slashes with CloudFront and 11ty

Intro This article will walk through the steps required to create a Cloudfront function to handle redirecting trailing slash URIs to non-trailing slash equivalents on your S3 hosted 11ty website. Background Several years ago we published our website at Si Novi using a hand-balled static site generator we built for ourselves, and deployed it to S3 with Cloudfront used for caching and routing our A…

Enhance CSRF package - now supports multipart form data

I've just published a minor update to my CSRF plugin for Enhance projects . v0.9.0 now supports multipart/form data, meaning you can easily use the <csrf-form></csrf-form> component for forms that contain file uploads. usage: <csrf-form method="post" action="/upload" enctype="multipart/form-data"> <input type="file" name="file" /> </csrf-form> outputs: <form…

DynamoDB Streams locally with arc.codes & Enhance

Introduction When working on a recent web app project using Enhance , I encountered a requirement for using both transactions and DynamoDB streams, two DynamoDB features that aren't supported by Dynalite - the fast in-memory DynamoDB engine that Architect uses to support local development. In this article, I'll introduce my new plugin ( arc-plugin-sandbox-stream ) for working with DynamoDB streams…

A mistake the internet won&#39;t forget easily

tldr : If you visited my site between 2022-12-01 and 2022-12-18 you might not be seeing updated content on previously accessed pages. I've added a Clear-Site-Data header to this page to possibly rectify. If you don't see multiple blogs posts on the homepage after viewing this article, please manually refresh any page you previously visited - thank you 🙏 edit: 2022-12-20 - Following a brief…

Eleventy 2.0 & WebC

I recently rebuilt this website and my company website - sinovi.uk - using Eleventy 2.0 and their new WebC language for templating. It's really good. And well worth checking out. In this post I look at my experiences trying out Eleventy 2.0 and its new Web Component language, WebC. Note At the time of writing 11ty 2.0 is pre-release. It’s just hit version canary-20 and judging by 11ty's recent…

Sharing Enhance elements between projects

This post introduces a new arc plugin for Enhance projects that I've recently published, with the catchy name shared-enhance-components-plugin . Read on for details about how to use the plugin and why I came to write it. Background While I continued my exploration of the Enhance framework, I started to wonder how you'd go about importing elements from a shared library or UI toolkit. In a React…

Back to the Future

As 2022 draws to a close I wanted to reflect on a welcome change in the web framework world that shifts the needle back towards web-first principles. Which I'm all here for. This year I’ve worked on a large web application using Remix , and the past week I’ve finally had free time to properly explore Enhance - something I've been super excited about since it was announced back in late Summer 2022.…