Posted by Dylan Beattie on 20 August 2025
•
permalink
I’ve spent most of the summer so far writing a new course; if you follow me over on BlueSky - and you should - then you’ll have noticed I’ve been posting - skeeting? bleeting? I still don’t know what to call posting on BlueSky. Let’s go with bleeting. I’ve been bleeting about CSS a lot, because my new course is CSS for Software Engineers. The video course is going to be available on Dometrain later this year, I’ll be running it as a workshop at various conferences, and I have a funny feeling there might even be a book at the end of it… but that’s taking up pretty much all my time, not to mention brain capacity, and hasn’t left a whole lot of time for YouTube videos and stuff.
But, it’s nearly September (yeah, really), which means it’s nearly conference season again, and I’m going to be bouncing around Europe for the next few months talking about all kinds of things - machine learning, text encoding, Rockstar, open source, and, yep, CSS.
Now, here’s the thing. When folks like me get invited to speak at these kinds of events, the organisers really appreciate it when we make a bit of noise about it, post it on social media, blog about it, make videos… and I get it; marketing is tough, every bit of coverage might help shift a few more tickets, and the algorithms that drive social media apparently love short form portrait videos… but, y’know, I’m forty seven years old, I listen to Bon Jovi and I still don’t really understand what TikTok is for; somebody like me making a video on my phone about a .NET developer conference and hoping it’ll go viral is… I believe they call it “cringe”.
But then I remember a few years ago I was in Tartu, in Estonia, where I was giving the keynote at digit.dev, and somebody recognised me in the street from my YouTube videos and we got chatting… turns out they’re a developer, they love code, they really liked my conference talks, and they had no idea that I was the keynote speaker at a multitrack international conference taking place right in the city where they live. And Tartu’s not a big place; it’s got about 100,000 people.
So here’s the deal. I’m going to tell you where I’m going, on the off-chance that you’re local, and you have some training budget left, because it would really suck if there was an awesome event happening right there in your home town and you didn’t know about it.
If you want a whole “ten reasons you can’t afford to miss OpenTechDevConDays 2025”… well, nah. Not really my jam. They have marketing people for that.
For what it’s worth, I do try to make sure that every event I’m involved with is excellent; I put a huge amount of work into preparing talks and workshops, I bring stickers to give away, and I try to make sure I have as much time as I can to meet people, hang out and chat about what you’re all working on.
So here’s where I’m going to be. I’m obviously not expecting any of you to come along to all of these - although I’ll be very impressed if you do - but if I’m going to be in your neighbourhood, and if you can persuade your company to buy a ticket, then come along and say hi.
I did mention I’ll be giving away Rockstar stickers, right?
September 8-12th I’ll be at NDC Copenhagen, where I’m running a brand new workshop about all the amazing things modern CSS can do. I’ll be giving a talk about algorithms and why they’re not as scary as they look, and probably eating quite a lot of barbecue at Warpigs.
September 25th I’ll be Edinburgh at ScotSoft 2025 talking about plain text: weird and wonderful stories about teletype machines, Hungarian Scrabble, how emojis actually work, and what “PIKE MATCHBOX” has to do with driving in the Soviet Union.
October 3rd I’ll be in Dordrecht in the Netherlands with Fronteers; that one’s a one-track evening conference, so should be a lot of fun; we haven’t finalised all the details for that one yet, but keep an eye on https://www.fronteers.nl/ for more news.
October 9th + 10th, I’ll be in Riga for Zabbix Summit. Zabbix is an open source observability and monitoring platform, so the event’s all about infrastructure, automation and devops; I’m going to be talking about the history and future of free software and how we might be able to create a truly sustainable model for open source development.
Then I’m in Portugal for two weeks; October 13-16 is the Azure Developer Summit in Lisbon, a brand new event organised by Microsoft in partnership with NDC and Techorama, all about Azure, AI, .NET, C# - and then 20-24 October it’s NDC Porto, which has a different format this year; instead of one-hour conference sessions it’s all hands-on workshops. I’m doing two days about modern CSS, plus a session about building a ray tracer in JavaScript, and another one about how to build your own programming language using C# and .NET and parsing expression grammars.
Then I’m home for two days, then a Eurostar to Rotterdam and on to Utrecht, where by a happy coincidence Techorama is in town the same week as Tweakers Summit. ***Monday 27th October*** I’ll be at Techorama with a one-day Introduction to Distributed Systems with .NET workshop, Tuesday 27th I’ll at Techorama in the morning and then heading to DeFabrique to close the Tweakers Summit, then I’m back at Techorama on Wednesday.
And then November 5-7 I’m at Øredev in Malmö, where I’ll be telling the story of how I built a Rockstar interpreter in web assembly using C#, and rocking the party stage with The Linebreakers.
Oh, and if you’re thinking “wow, that’s not nearly enough travelling, this guy isn’t even trying any more”, I’m also going to the Euroblast festival in Cologne at the end of September, and heading to Yorkshire for the Whitby Goth Weekend at the end of October. Not performing or anything, just going along to watch bands and have fun. You know. Like a normal person.
So that’s, what, nine tech events - and two music festivals - in seven countries in two months. It’s going to be . Come along and say hi.
Right now, though, I gotta get back to writing about how CSS flexbox actually works, which turns out to involve way more mathematics than you might think.
"On The Road Again..." was posted by Dylan Beattie on 20 August 2025
•
permalink
CSS Has 239 Different Ways To Make Something Blue
Posted by Dylan Beattie on 30 July 2025
•
permalink
I’m making a new video course for Dometrain at the moment, and it’s all about CSS - one of the three pillars of the open web, along with HTML and JavaScript. I love CSS, I’ve been working with it literally since it was invented, but I absolutely understand why so many developers don’t enjoy working with it.
CSS has had to incorporate conventions and standards from a wider range of disciplines than any other mainstream technology. Modern CSS incorporates ideas from mechanical typesetting dating back centuries, conventions around information design from hundreds of years of printing and publishing, fifty years of innovations from digital publishing and computer graphics, twenty years of getting stuff wrong on the web while we were still figuring out how to get it right - right up to things like how to account for the “dynamic island” on the latest iPhone handsets.
To say it’s accumulated a few idiosyncrasies along the way would be an understatement. Yesterday, while putting together the module about how the various colours models work in CSS, I found myself wondering how many different ways there are in modern CSS to give a box a blue background.
You’ve probably heard of named colours (color: blue;), and hex codes (color: #0000ff). Hex codes can also be written as three digits (#00f), four digits (#00ff), and eight digits (#0000ffff).
Then there’s the rgb() function, which can take each colour component as a decimal or as a percentage. There’s hsl(), which takes hue, saturation, and lightness, along with a bunch of new colour models - hwb(), lab(), lch, oklab() and oklch() - all of which also take a hue component.
Except hue in CSS is an angle - the colour’s position on a colour wheel - and CSS already has a unit system in place for angles, that’s used for rotations and transformation, so the colour models just reuse that. Which means you can write the hue component as degrees (with or without deg), radians, gradians (the cursed unit. 400 grads in a circle. Why does it even exist? I don’t know.), or turns. So if any colour specification involves hue, there are five different ways to write it.
Add in two different ways to specify alpha transparency - / 100% and / 1.0 - and you end up with well over two hundred different ways to say “the box is blue”… and this is just using the modern CSS colour syntax; we’re not even getting into the legacy rgb() and hsl() function syntax, their aliases rgba() and hsla(), or any of the wonderful things you can do with calc() and relative colours.
OK, let’s be fair here. If the language designers hadn’t reused CSS angular units for hue, we’d be
looking at more like 40, maybe 50 syntax variants. Pick a lane for how you want to specify transparency, you’re down to 20 or so. You’re very unlikely to use the LAB or LCH colour models in production unless you know exactly what you’re doing, so that’ll chop it down further; in reality, you’re not going to encounter more than handful of these variants, and the vast majority of sites out there just use hex codes for everything.
But, y’know, if you’ve got the whole chaotic evil vibe going on, why not spec all your colours as oklch, lightness and chroma as arbitrary decimals, hue in grads, and give everything an alpha channel
that’s randomly a percentage or a decimal, even for colours which are fully opaque?
I think you’ll all agree that color: blue; looks kinda dumb, but color: oklch(0.452 0.31 292grad / 100%); is clearly the work of a genius.
"CSS Has 239 Different Ways To Make Something Blue" was posted by Dylan Beattie on 30 July 2025
•
permalink
Naming Things is Hard... Renaming Things is Harder
Posted by Dylan Beattie on 26 July 2025
•
permalink
You know those little things that you just sort of ignore, over over and over again, until finally one day the planets align and you’re like “No! I’m not putting up with this any more! There must be a way to fix it!”
Welcome to my cameras. I have two Canon EOS M200 cameras, which I use for streaming, recording training videos, teaching online workshops, all kinds of stuff. One is black, one is white, they are otherwise identical. They’re both connected to my main PC using Elgato Cam Link 4K HDMI capture devices, which for the remainder of this article I will call camlinks because they don’t have a better generic name.
They’re also connected using micro-USB, which means I can use Canon’s Remote Shooting utility to control things like the F-stop, white balance, and ISO. The cameras themselves are permanently mounted around my desk — one is above my main screen, the other one’s built in to a teleprompter — so it’s kinda hard to fiddle with the settings menu.
The problem is that when I go to fire up the EOS utility, it asks me to pick which camera I’m using… am I using the Canon EOS M200, or the Canon EOS M200? And then there’s the fact that both of the dongles show up in Windows as “Cam Link 4K”, which means setting up video sources in programs like OBS Studio normally involves picking the wrong camera at least once.
Well, this morning I had that fateful nerd thought… “I should fix this. How hard can it be?” Well, grab your razor and strap in, friends… we’re going yak shaving!
Now, most of the time, if you want to rename a thing in Windows, you right-click it, and choose “Rename”, and give it a new name.
That doesn’t work in Device Manager. I mean, sure, rename a file, but why would anybody ever need to rename a camera?
OK, no big deal. Those names have got to come from somewhere. Probably the registry. So I fire up regedit, Ctrl-F, “Cam Link 4K”, hit “Find Next”:
And I wait, and wait, and wait a bit, and then I get bored because this is a Ryzen 9950X3D with 128Gb of RAM and I didn’t spend that kind of money so I could sit around and wait for things, dammit!
I tried writing a Powershell script to do the same thing — trawl the registry, look at all the keys and subkeys and entries and values — but it did that infuriating thing where it takes so long to not do anything that it wasn’t clear after 30 seconds whether the program worked, but hadn’t matched anything, or I’d screwed up the matching logic.
Ok, much better approach: let’s dump the entire system registry to a text file and then I can edit it properly. File, Export, registry.txt, takes about a second. Done.
I now have a 540Mb text file full of bits of Windows registry. It looks like this:
So I want to find every chunk that contains any entry whose value contains "Cam Link 4K" or "Canon EOS M200", and then extract:
The first row of that chunk, which is the path to the registry key I need to edit
The entry itself
Then — in theory — I’ve got a handful of registry entries in a file, which I can edit in VS Code or something, import it into regedit, and presto! rename all the things.
First idea: pull it into VS Code, replace all the \n with a marker __EOL__ so I get every block on its own line, delete all the lines that don’t contain "Cam Link 4K" or "Canon EOS M200", turn all the __EOL__ back into \n, and then do the rest by hand.
Yeah… VS Code won’t do that.
TextPad wouldn’t do it either…
But it's OK. We solved this problem. We solved it BEFORE I WAS BORN. The beardy wizard people who created Unix knew all about editing files that wouldn't fit in memory, because they built Unix for computers that had an ENTIRE MEGABYTE of RAM... which you had to share with the rest of the university.
Yep, this is a job for awk. You probably don’t know what awk is. Awk is a stream-based editing utility originally created for Unix. So I asked Copilot to write me an awk script. (what, you think I can remember how to write awk? University was a long time ago, friends…)
BEGIN{RS="\n\n";# Blank lines separate records (blocks)ORS="\n\n";# Output blocks separated by two newlines}{if($0~/Cam Link 4K || $0 ~ /CanonEOSM200/){n=split($0,lines,"\n")output=lines[1]for(i=2;i<=n;i++){if(lines[i]~/Cam Link 4K/||lines[i]~/Canon EOS M200/){output=output"\n"lines[i]}}printoutput}}
Yeah, that’s what awk looks like. Remember, this is the language that Larry Wall looked at, went “well, golly,I can do better than that”, and… invented Perl.
Of course, it didn’t work. Me & my little electric copilot buddy had missed two rather significant details… first, the RS record separator? We’re trawling a file created by Windows regedit. It’s using \r\n, not \n. Easy fix; change `RS = “\r?\n\r?\n” `(and look, now it’ll work cross-platform if I ever need to awk the Windows registry on macOS!)
Still doesn’t work… because the Windows Registry Editor’s Export feature creates text files that are encoded as UTF16-LE, and awk don’t do UTF16. So I use VS Code to save the registry file as UTF-8, and off we go…
gawk -f filter.awk registry.txt > devices.txt
It works!devices.txt now has a little registry snippet for every single chunk of registry that includes "Canon EOS M200" or "Cam Link 4K"…
"Canon EOS M200" appears 25 times in the registry.
"Cam Link 4K" appears 60 times - and the exact entry "FriendlyName"="Cam Link 4K" accounts for 41 of those... crikey.
That's a lot of times.
I am assuming at this point that nothing in Windows is stupid enough to actually open, connect, etc. devices based on a field called FriendlyName. If I’m wrong, things are about to get extremely hilarious indeed.
So I use Textpad’s really handy “sequence replace” feature, that’ll let you use a regex to find something and then include an incrementing sequence number in the replacement expression:
The result is a registry file where every FriendlyName value is now unique - so I can in theory reboot, see which names appear in which drop-down menus and dialogs, and then edit them accordingly. In theory.
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Portable Devices\Devices\USB#VID_04A9&PID_32EF#9&39F7FE61&0&3]
"FriendlyName"="Canon EOS M200 UNIQUE12"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Portable Devices\Devices\USB#VID_04A9&PID_32EF#A&D9BD236&0&3]
"FriendlyName"="Canon EOS M200 UNIQUE13"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{eec5ad98-8080-425f-922a-dabf3de3f69a}\0005]
"FriendlyName"="Canon EOS M200 UNIQUE14"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{eec5ad98-8080-425f-922a-dabf3de3f69a}\0009]
"FriendlyName"="Canon EOS M200 UNIQUE15"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_04A9&PID_32EF\9&39f7fe61&0&3]
"FriendlyName"="Canon EOS M200 UNIQUE38"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_04A9&PID_32EF\a&d9bd236&0&3]
"FriendlyName"="Canon EOS M200 UNIQUE39"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_0FD9&PID_0066&MI_00\a&1b1e3ad0&0&0000]
"FriendlyName"="Cam Link 4K UNIQUE40"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_0FD9&PID_0066&MI_03\a&1b1e3ad0&0&0003]
"FriendlyName"="Cam Link 4K UNIQUE41"
Add the first line to the file otherwise regedit rejects it:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Portable Devices\Devices\USB#VID_04A9&PID_32EF#9&39F7FE61&0&3]
"FriendlyName"="Canon EOS M200 UNIQUE12"
...and so on...
Import…
Reboot… IT WORKED!
Well, it worked mostly. At first, the Canon EOS Utility Launcher didn’t pick it up at all, and it turns out some of the Canon EOS utilities read the DeviceDesc value from the registry, not FriendlyName, so I edited that one too… at this point I got into a good half-hour of editing something, rebooting, seeing what had changed, edit again, reboot again, turn it off and on again… and quite a few moments where I thought I’d tried everything I could think of, including a reboot, and it still hadn’t worked…
And then, one final, glorious reboot, and there it was.
And you know what?
I will bet money, good, solid, chunky cash dollar money, that at some point, somebody at Canon said “er… boss, what happens if somebody buys two of the same camera, and has them both plugged in at the same time over USB?” and somebody’s boss said words to the effect of “stop derailing the planning meeting with your stupid edge cases, Chris, we have work to do and you’re not helping.”
I see you, Chris.
I see you, and I salute you. 🫡
Oh, and Microsoft: if we could get right-click, Rename… in the Device Manager? That’d be, like, just swell.
"Naming Things is Hard... Renaming Things is Harder" was posted by Dylan Beattie on 26 July 2025
•
permalink
The Subtle Art Of Deprecating API Endpoints
Posted by Dylan Beattie on 16 July 2025
•
permalink
I had an app fail in production the other day. Not seriously - only affected a couple of admin screens - but it failed because Hubspot had deprecated some of their API endpoints. (That’s nerd speak for “we were using a thing and they turned it off.”)
Sure, they announced in October 2024 that this particular endpoint was being deprecated. Only problem is… I didn’t see the announcement, because I didn’t even start working on this integration until April 2025 - in fact, I’d never worked with Hubspot’s API at all prior to April 2025. I followed their docs, built the integration points I needed, tested it all… and I somehow managed to build and test an integration against an endpoint which was already scheduled for deprecation, without ever having the faintest clue.
Wouldn’t it be nice if, the day they decide something’s going to get switched off, that feature was no longer available to any new customers? Sure, the folks who were already using it before the announcement; makes sense to give them six months or whatever to update their code. But seems a bit odd to me that they’d offer completely new integrations access to a feature they already know is going to shut down soon.
..then again, maybe I’m just salty ‘cos I don’t like it when other people break my stuff. I guess the lesson is to always assume that every single API request you make might randomly start returning an HTTP 400, at any point, for no good reason, and engineer around that as best you can. Fallback caching actually kept the thing running for at least a week after the endpoint in question was deprecated, which I’m kinda happy about - but I could also have wired it to actually tell somebody if it had been running on cached data for more than 24 hours.
"The Subtle Art Of Deprecating API Endpoints" was posted by Dylan Beattie on 16 July 2025
•
permalink
We Miss You, Tommy Vance
Posted by Dylan Beattie on 06 July 2025
•
permalink
In 1990, BBC Radio 1 broadcast the “Monsters of Rock” festival live from Donington Park. Thunder, Quireboys, Poison, Aerosmith, Whitesnake - and before, between, and after the bands, the broadcast featured live commentary and interviews from Tommy Vance, Mick Wall roaming the backstage area talking to the stars who were in attendance, and Richard Skinner’s 4-part history of the Monsters of Rock. Free to air. I know this, ‘cos I recorded the whole thing onto a stack of TDK D90 tapes and listened to it on repeat for the better part of the next decade.
Today, five million people paid £25 each to watch the live stream of Ozzy Osbourne’s farewell show with Black Sabbath, broadcast live from Villa Park in Birmingham. That’s over a hundred million pounds in revenue, just from the live stream… so, of course, between the acts, the stream cut to a professional studio, where experienced presenters talked about the history and significance of the show, interviewed the stars who were performing live… no, of course it didn’t. Instead, we got 15-second cameraphone clips of Sabbath fans all over the world talking about how much they loved the band, interspersed with fundraiser clips from the various charities the day was nominally supporting.
The coverage of the live acts was impeccable, but the interludes made the whole thing feel like one of those “live in my living room” streams everybody was doing back in 2020, and… well, I can’t help thinking that if Tommy Vance was still around, he wouldn’t have let that happen on his watch. But he’s not, and I didn’t realise until today that maybe when TV died, the best part of rock’n’roll broadcasting died with him.
"We Miss You, Tommy Vance" was posted by Dylan Beattie on 06 July 2025
•
permalink