Last night I was chatting to my friend (and fellow Three Rings volunteer) Ollie about our respective
workplaces and their approach to AI-supported software engineering, and it echoed conversations I’ve had with other friends. Some workplaces, it seems, are leaning so-hard into
AI-supported software development that they’re berating developers who seem to be using the tools less than their colleagues!
That’s a problem for a few reasons, principal among them that AI does not
make you significantly faster but does make you learn less.1. I stand by the statement that AI isn’t useless, and I’ve experimented with it for years. But I certainly wouldn’t feel very comfortable
working somewhere that told me I was underperforming if, say, my code contributions were less-likely than the average to be identifiably “written by an AI”.
Even if you’re one of those folks who swears by your AI assistant, you’ve got to admit that they’re not always the best choice.
I ran into something a little like what Ollie described when an AI code reviewer told me off for not describing how my AI agent assisted me with the code change… when no AI had been
involved: I’d written the code myself.2
I spoke to another friend, E, whose employers are going in a similar direction. E joked that at current rates they’d have to start tagging their (human-made!) commits with fake
AI agent logs in order to persuade management that their level of engagement with AI was correct and appropriate.3
Supposing somebody like Ollie or E or anybody else I spoke to did feel the need to “fake” AI agent logs in order to prove that they were using AI “the right way”… that sounds
like an excuse for some automation!
I got to thinking: how hard could it be to add a git hook that added an AI agent’s “logging” to each commit, as if the work had been done by a
robot?4
Turns out: pretty easy…
To try out my idea, I made two changes to a branch. When I committed, imaginary AI agent ‘frantic’ took credit, writing its own change log. Also: asciinema + svg-term remains awesome.
Here’s how it works (with source code!). After you make a commit, the post-commit hook creates a file in
.agent-logs/, named for your current branch. Each commit results in a line being appended to that file to say something like [agent] first line of your commit
message, where agent is the name of the AI agent you’re pretending that you used (you can even configure it with an array of agent names and it’ll pick one at
random each time: my sample code uses the names agent, stardust, and frantic).
There’s one quirk in my code. Git hooks only get the commit message (the first line of which I use as the imaginary agent’s description of what it did) after the commit has
taken place. Were a robot really used to write the code, it’d have updated the file already by this point. So my hook has to do an --amend commit, to
retroactively fix what was already committed. And to do that without triggering itself and getting into an infinite loop, it needs to use a temporary environment variable.
Ignoring that, though, there’s nothing particularly special about this code. It’s certainly more-lightweight, faster-running, and more-accurate than a typical coding LLM.
Sure, my hook doesn’t attempt to write any of the code for you; it just makes it look like an AI did. But in this instance: that’s a feature, not a
bug!
Footnotes
1 That research comes from Anthropic. Y’know, the company who makes Claude, one of the
most-popular AIs used by programmers.
3 Using “proportion of PRs that used AI” as a metric for success seems to me to be just
slightly worse than using “number of lines of code produced”. And, as this blog post demonstrates, the
former can be “gamed” just as effectively as the latter (infamously) could.
4 Obviously – and I can’t believe I have to say this – lying to your employer isn’t a
sensible long-term strategy, and instead educating them on what AI is (if anything) and isn’t good for in your workflow is a better solution in the end. If you read this blog post and
actually think for a moment hey, I should use this technique, then perhaps there’s a bigger problem you ought to be addressing!
Today, an AI review tool used by my workplace reviewed some code that I wrote, and incorrectly claimed that it would introduce a bug because a global variable I created could “be
available to multiple browser tabs” (that’s not how browser JavaScript works).
Just in case I was mistaken, I explained to the AI why I thought it was wrong, and asked it to explain itself.
To do so, the LLM wrote a PR to propose adding some code to use our application’s save mechanism to pass the data back, via the server, and to any other browser tab, thereby creating
the problem that it claimed existed.
This isn’t even the most-efficient way to create this problem. localStorage would have been better.
So in other words, today I watched an AI:
(a) claim to have discovered a problem (that doesn’t exist),
(b) when challenged, attempt to create the problem (that wasn’t needed), and
(c) do so in a way that was suboptimal.
Humans aren’t perfect. A human could easily make one of these mistakes. Under some circumstances, a human might even have made two of these mistakes. But to make all three? That took an
AI.
What’s the old saying? “To err is human, but to really foul things up you need a computer.”
Highlight of my workday was debugging an issue that turned out to be nothing like what the reporter had diagnosed.
The report suggested that our system was having problems parsing URLs with colons in the pathname, suggesting perhaps an encoding issue. It wasn’t until I took a deep dive into the logs
that I realised that this was a secondary characteristic of many URLs found in customers’ SharePoint installations. And many of those URLs get redirected. And SharePoint often uses
relative URLs when it sends redirections. And it turned out that our systems’ redirect handler… wasn’t correctly handling relative URLs.
It all turned into a hundred line automated test to mock SharePoint and demonstrate the problem… followed by a tiny two-line fix to the actual code. And probably the
most-satisfying part of my workday!
Further analysis on a smaller pcap pointed to these mysterious packets arriving ~20ms apart.
This was baffling to me (and to Claude Code). We kicked around several ideas like:
SSH flow control messages
PTY size polling or other status checks
Some quirk of bubbletea or wish
One thing stood out – these exchanges were initiated by my ssh client (stock ssh installed on MacOS) – not by my server.
…
In 2023, ssh added keystroke timing obfuscation. The idea is that the speed at
which you type different letters betrays some information about which letters you’re typing. So ssh sends lots of “chaff” packets along with your keystrokes to make it hard for an
attacker to determine when you’re actually entering keys.
That makes a lot of sense for regular ssh sessions, where privacy is critical. But it’s a lot of overhead for an open-to-the-whole-internet game where latency is critical.
…
Keystroke timing obfuscation: I could’ve told you that! Although I wouldn’t necessarily have leapt to the possibility of mitigating it server-side by patching-out support for (or at
least: the telegraphing of support for!) it; that’s pretty clever.
Altogether this is a wonderful piece demonstrating the whole “engineer mindset”. Detecting a problem, identifying it, understanding it, fixing it, all tied-up in an engaging narrative.
And after playing with his earlier work, ssh tiny.christmas – which itself inspired me to learn a little Bubble Tea/Wish (I’ve got Some Ideas™️) – I’m quite excited to see where this new
ssh-based project of Royalty’s is headed!
This is a blog post about things that make me nostalgic for other things that, objectively, aren’t very similar…
When I hear Dawnbreaker, I feel like I’m nine years old…
…and I’ve been allowed to play OutRun on the arcade cabinet at West View
Leisure Centre. My swimming lesson has finished, and normally I should go directly home.
On those rare occasions I could get away1
with a quick pause in the lobby for a game, I’d gravitate towards the Wonderboy machine. But there was something about the tactile
controls of OutRun‘s steering wheel and pedals that gave it a physicality that the “joystick and two buttons” systems couldn’t replicate.
The other thing about OutRun was that it always felt… fast. Like, eye-wateringly fast. This was part of what gave it such appeal2.
OutRun‘s main theme, Magical Sound Shower, doesn’t actually sound much like Dawnbreaker. But
both tracks somehow feel like… “driving music”?
But somehow when I’m driving or cycling and it this song comes on, I’m instantly transported back to those occasionally-permitted childhood games of OutRun4.
When I start a new Ruby project, I feel like I’m eleven years old…
It’s not quite a HELLO WORLD, but it’s pretty-similar.
At first I assumed that the tedious bits and the administrative overhead (linking, compiling, syntactical surprises, arcane naming conventions…) was just what “real”, “grown-up”
programming was supposed to feel like. But Ruby helped remind me that programming can be fun for its own sake. Not just because of the problems you’re solving or the product
you’re creating, but just for the love of programming.
The experience of starting a new Ruby project feels just like booting up my Amstrad CPC and being able to joyfully write code that will just work.
I still learn new programming languages because, well, I love doing so. But I’m yet to find one that makes me want
to write poetry in it in the way that Ruby does.
When I hear In Yer Face, I feel like I’m thirteen years old…
…and I’m painting Advanced HeroQuest miniatures6 in the attic at my dad’s house.
I’ve cobbled together a stereo system of my very own, mostly from other people’s castoffs, and set it up in “The Den”, our recently-converted attic7,
and my friends and I would make and trade mixtapes with one another. One tape began with 808 State’s In Yer Face8,
and it was often the tape that I would put on when I’d sit down to paint.
Advanced HeroQuest came with some fabulously ornate secondary components, like the doors that were hinged so their their open/closed state could be toggled, and I spent
way too long painting almost the entirety of my base set.
In a world before CD audio took off, “shuffle” wasn’t a thing, and we’d often listen to all of the tracks on a medium in sequence9.
That was doubly true for tapes, where rewinding and fast-forwarding took time and seeking for a particular track was challenging compared to e.g. vinyl. Any given song would loop around
a lot if I couldn’t be bothered to change tapes, instead just flipping again and again10.
But somehow it’s whenever I hear In Yer Face11
that I’m transported right back to that time, in a reverie so corporeal that I can almost smell the paint thinner.
When I see a personal Web page, I (still) feel like I’m fifteen years old…
…and the Web is on the cusp of becoming the hot “killer application” for the Internet. I’ve been lucky enough to be “online” for a few years by now12,
and basic ISP-provided hosting would very soon be competing with cheap, free, and ad-supported services like Geocities to be “the
place” to keep your homepage.
Nowadays, even with a hugely-expanded toolbox, virtually every corporate homepage fundamentally looks the same:
Logo in the top left
Search and login in the top right, if applicable
A cookie/privacy notice covering everything until you work out the right incantation to make it go away without surrendering your firstborn child
A “hero banner“
Some “below the fold” content that most people skip over
A fat footer with several columns of links, to ensure that all the keywords are there so that people never have to see this page and the search engine will drop
them off at relevant child page and not one of their competitors
Finally, a line of icons representing various centralised social networks: at least one is out-of-date, either because (a) it’s been renamed, (b) it’s changed its
branding, or (c) nobody with any moral fortitude uses that network any more14
But before the corporate Web became the default, personal home pages brought a level of personality that for a while I worried was forever dead.
2 Have you played Sonic Racing: CrossWorlds? The first time I played it I was overwhelmed by the speed and colours of the
game: it’s such a high-octane visual feast. Well that’s what OutRun felt like to those of us who, in the 1980s, were used to much-simpler and slower arcade games.
3 Also, how cool is it that Metrik has a blog, in this day and age? Max props.
4 Did you hear, by the way, that there’s talk of a movie adaptation of OutRun, which could turn out to be the worst
videogame-to-movie concept that I’ll ever definitely-watch.
5 In very-approximate order: C, Assembly, Pascal, HTML, Perl, Visual Basic (does that even
count as a “grown-up” language?), Java, Delphi, JavaScript, PHP, SQL, ASP (classic, pre-.NET), CSS, Lisp, C#, Ruby, Python (though I didn’t get on with it so well), Go, Elixir… plus
many others I’m sure!
6 Or possibly they were Warhammer Quest miniatures by this point; probably this memory spans one, and also the other, blended together.
7 Eventually my dad and I gave up on using the partially-boarded loft to intermittently
build a model railway layout, mostly using second-hand/trade-in parts from “Trains & Transport”, which was exactly the nerdy kind of model shop you’re imagining right now: underlit
and occupied by a parade of shuffling neckbeards, between whom young-me would squeeze to see if the mix-and-match bin had any good condition HO-gauge flexitrack. We converted the
attic and it became “The Den”, a secondary space principally for my use. This was, in the most part, a concession for my vacating of a large bedroom and instead switching to the
smallest-imaginable bedroom in the house (barely big enough to hold a single bed!), which in turn enabled my baby sister to have a bedroom of her own.
8 My copy of In Yer Face was possibly recorded from the radio by my friend ScGary, who always had a tape deck set up with his finger primed close to the record key when the singles chart came on.
9 I soon learned to recognise “my” copy of tracks by their particular cut-in and -out
points, static and noise – some of which, amazingly, survived into the MP3 era – and of course the tracks that came before or after them, and
there are still pieces of music where, when I hear them, I “expect” them to be followed by something that they used to some mixtape I listened to a lot 30+ years
ago!
10 How amazing a user interface affordance was it that playing one side of an audio
cassette was mechanically-equivalent to (slowly) rewinding the other side? Contrast other tape formats, like VHS, which were one-sided and so while rewinding there was
literally nothing else your player could be doing. A “full” audio cassette was a marvellous thing, and I especially loved the serendipity where a recognisable “gap” on one
side of the tape might approximately line-up with one on the other side, meaning that you could, say, flip the tape after the opening intro to one song and know that you’d be
pretty-much at the start of a different one, on the other side. Does any other medium have anything quite analogous to that?
11 Which is pretty rare, unless I choose to put it on… although I did overhear it
“organically” last summer: it was coming out of a Bluetooth speaker in a narrowboat moored in the Oxford Canal near Cropredy, where I was using the towpath to return from a long walk to nearby Northamptonshire where I’d been searching for a geocache. This was a particularly surprising
place to overhear such a song, given that many of the boats moored here probably belonged to attendees of Fairport’s Cropredy Convention, at which – being a folk music festival – one
might not expect to see significant overlap of musical taste with “Madchester”-era acid house music!
12 My first online experiences were on BBS systems, of which my very first was on a
mid-80s PC1512 using a 2800-baud acoustic coupler! I got onto the Internet at a point in the early 90s at which the Web
existed… but hadn’t yet demonstrated that it would eventually come to usurp the services that existed before it: so I got to use Usenet, Gopher, Telnet and IRC before I saw
my first Web browser (it was Cello, but I switched to Netscape Navigator soon after it was released).
13 On the rare occasion I close my browser, these days, it re-opens with whatever
hundred or so tabs I was last using right back where I left them. Gosh, I’m a slob for tabs.
14 Or, if it’s a Twitter icon: all three of these.
15 Of course, they’re harder to find. SEO-manipulating behemoths dominate the search
results while social networks push their “apps” and walled gardens to try to keep us off the bigger, wider Web… and the more you cut both our of your online life, the calmer and
happier you’ll be.
This weekend, I received my copy of DOCTYPE, and man: it feels like a step back to yesteryear to type in a computer program from a
magazine: I can’t have done that in at least thirty years.
So yeah, DOCTYPE is a dead-tree (only) medium magazine containing the source code to 10 Web pages which, when typed-in to your computer, each provide you with some kind of fun and
interactive plaything. Each of the programs is contributed by a different author, including several I follow and one or two whom I’m corresponded with at some point or another, and each
brings their own personality and imagination to their contribution.
I opted to start with Stuart Langridge‘s The Nine Pyramids, a puzzle game about trying to connect all nodes in a 3×3 grid in a
continuous line bridging adjacent (orthogonal or diagonal) nodes without visiting the same node twice nor moving in the same direction twice in a row (that last provision is described
as “not visiting three in a straight line”, but I think my interpretation would have resulted in simpler code: I might demonstrate this, down the line!).
The puzzle actually made me stop to think about it for a bit, which was unexpected and pleasing!
Per tradition with this kind of programming, I made a couple of typos, the worst of which was missing an entire parameter in a CSS conic-gradient() which resulted in the
majority of the user interface being invisible: whoops! I found myself reminded of typing-in the code for Werewolves and
Wanderer from The Amazing Amstrad Omnibus, whose data section – the part most-liable to be affected by a typographic bug without introducing a syntax error – had
a helpful “checksum” to identify if a problem had occurred, and wishing that such a thing had been possible here!
But thankfully a tiny bit of poking in my browser’s inspector revealed the troublesome CSS and I was able to complete the code, and then the puzzle.
I’ve really been enjoying DOCTYPE, and you can still buy a copy if you’d like one of your own. It manages to simultaneously feel both fresh and nostalgic,
and that’s really cool.
The younger child and I were talking about maths on the school run this morning, and today’s topic was geometry. I was pleased to discover that he’s already got a reasonable
comprehension of the Pythagorean Theorem1:
I was telling him that I was about his age when I first came across it, but in my case I first had a practical, rather than theoretical, impetus to learn it.
It was the 1980s, and I was teaching myself Dr. Logo, Digital Research‘s implementation of the Logo programming language (possibly from this book). One day, I was writing a program to draw an indoor scene, including a window
through which a mountain would be visible. My aim was to produce something like this:
My window was 300 “steps”2
tall by 200 steps wide and bisected in both directions when I came to make my first attempt at the mountain.
And so, naively, starting from the lower-left, I thought I’d need some code like this:
RIGHT 45
FORWARD 100
RIGHT 90
FORWARD 100
But what I ended up with was this:
Hypotenuse? More like need-another-try-potenuse.
I instantly realised my mistake: of course the sides of the mountain would need to be longer so that the peak would reach the mid-point of the window and the far side
would hit its far corner. But how much longer ought it to be.
I intuited that the number I’d be looking for must be greater than 100 but less than 250: these were, logically, the bounds I was working within. 100 would be correct if my
line were horizontal (a “flat” mountain?), and 250 was long enough to go the “long way” to the centrepoint of the window (100 along, and 150 up). So I took a guess at 150 and… it was
pretty close… but still wrong:
I remember being confused and frustrated that the result was so close but still wrong. The reason, of course, is that the relationship between the lengths of the sides of a triangle
don’t scale in a 1:1 way, but this was the first time I found myself having to think about why.
So I found my mother and asked her what I was doing wrong. I’m sure it must have delighted her to dust-off some rarely-accessed knowledge from her own school years and teach me about
Pythagoras’!
The correct answer, of course, is given by:
I so rarely get to use MathML that I had to look up the syntax.
The answer, therefore, is… 141.421 (to three decimal places). So I rounded to 141 and my diagram worked!3
What made this maths lesson from my mother so memorable was that it fed a tangible goal. I had something I wanted to achieve, and I learned the maths that I
needed to get there. And now it’s impermeably etched onto my brain.
I learned the quadratic equation formula and how to perform algebraic integration by rote, and I guarantee that it’s less well-established in my long-term memory than, say, the sine and
cosine rules or how to solve a simultaneous equation because I’ve more-often needed to do those things outside of the classroom!
So I guess the lesson is that I should be trying to keep an eye out for practical applications of maths that I can share with my kids. Real problems that are interesting to solve, to
help build the memorable grounding that latter supports the more-challenging and intangible abstract maths that they may wish to pursue later.
Both kids are sharp young mathematicians, and the younger one seems especially to enjoy it, so feeding that passion feels well-worthwhile. Perhaps I should show them TRRTL.COM so they can try their hand at Logo!
2 Just one way that Logo is/was a cute programming language was its use of “steps” – as
in, turtle-steps – to measure distances. You might approximate them as pixels, but a “step” has meaning even for lines that don’t map linearly to pixels because they’re at wonky
angles, for example.
3 I’d later become unstuck by rounding, while trying to make a more-complex diagram with a
zig-zag pattern running along a ribbon: a small rounding error became compounded over a long time and lead to me being a couple of pixels off where I intended. But that’s another
story.
I nerdsniped myself today when, during a discussion on the potential location of a taekwondo tournament organised by our local martial arts school, somebody claimed that Scotland would be “nearer”
than Ireland.
I don’t dispute that somebody living near me can get to Scotland faster than Ireland, unless they can drive at motorway speeds across Wales… and the Irish Sea. But the word
they used was nearer, and I can be a pedantic arse.
But the question got me thinking:
Could I plot a line across Great Britain, showing which parts are closer to Scotland and which parts are closer to Ireland?
If the England-facing Irish and Scottish borders were completely straight, one could simply extend the borders until they meet, bisect the angle, and we’d be done.
Of course, the borders aren’t straight. They also don’t look much like this. I should not draw maps.
In reality, the border between England and Scotland is a winding mess, shaped by 700 years of wars and treaties1.
Treating the borders as straight lines is hopelessly naive.
Voronoi diagrams are pretty, and cool, and occasionally even useful! This one expands from points, but there’s no reason you can’t expand from a line (line a border!) instead.
My Python skills are pretty shit, but it’s the best tool for the job for geohacking2. And so, through a
combination of hacking, tweaking, and crying, I was able to throw together a script that produces a wonderful
slightly-wiggly line up the country.
The entire island of Ireland is used here to determine boundaries (you can tell because otherwise parts of County Antrim, in Northern Ireland, would be marked as closer to Scotland
than the Republic of Ireland: which they are, of course, but the question was about England!).
Once you’ve bisected England in this way – into parts that are “closer to Ireland” versus parts that are “closer to Scotland”, you start to spot all kinds of interesting
things3.
Like: did you know that the entire subterranean part of the Channel Tunnel is closer to Scotland than it is to Ireland… except for the ~2km closest to the UK exit.
A little further North: London’s six international airports are split evenly across the line, with Luton, Stansted and Southend closer to Scotland… and City, Heathrow and Gatwick closer
to Ireland.
The line then pretty-much bisects Milton Keynes, leaving half its population closer to Scotland and half closer to Ireland, before doing the same to Daventry, before – near Sutton
Coldfield – it drives right through the middle of the ninth hole of the golf course at the Lea Marston Hotel.
Players tee off closer to Ireland and – unless they really slice it – their ball lands closer to Scotland:
In Cannock, it bisects the cemetery, dividing the graves into those on the Scottish half and those in the Irish half:
The line crosses the Welsh border at the River Dee, East of Wrexham, leaving a narrow sliver of Wales that’s technically closer to Scotland than it is to Ireland, running up the
coastline from Connah’s Quay to Prestatyn and going as far inland as Mold before – as is the case in most of Wales – you’re once again closer to Ireland:
If you live in Flint or Mold, ask your local friends whether they live closer to Ireland or Scotland. The answer’s Scotland, and I’m confident that’ll surprise them.
I’d never have guessed that there were any parts of Wales that were closer to Scotland than they were to Ireland, but the map doesn’t lie4
Anyway: that’s how I got distracted, today. And along the way I learned a lot about geodata encoding, a little about Python, and a couple of surprising things about geography5.
2 Or, at least: it’s the one that’s most-widely used and so I could find lots of helpful
StackOverflow answers when I got stuck!
3 Interesting… if you’re specifically looking for some geographical trivia, that is!
4 Okay, the map lies a little. My program was only simple so it plotted
everything on a flat plane, failing to accommodate for Earth’s curvature. The difference is probably marginal, but if you happen to live on or very close to the red line, you might
need to do your own research!
5 Like: Chester and Rugby are closer to Scotland than they are to Ireland, and Harpenden
and Towcester are closer to Ireland than they are to Scotland! Who knew?
Scroll art is a form of ASCII art where a program generates text output in a command line terminal. After the terminal window
fills, it begins to scroll the text upwards and create an animated effect. These programs are simple, beautiful, and accessible as programming projects for beginners. The SAM is a
online collection of several scroll art examples.
Here are some select pieces:
Zig-zag, a simple periodic pattern in a dozen lines of code.
Program output is limited to text (though this could include emoji and color.)
Once printed, text cannot be erased. It can only scroll up.
But these restrictions compel creativity. The benefit of scroll art is that beginner programmers can create scroll art apps with a minimal amount of experience. Scroll art
requires knowing only the programming concepts of print, looping, and random numbers. Every programming langauge has these features, so scroll art can be created in
any programming language without additional steps. You don’t have to learn heavy abstract coding concepts or configure elaborate software libraries.
…
Okay, so: scroll art is ASCII art, except the magic comes from the fact that it’s very long and as your screen scrolls to show it, an animation effect becomes apparent. Does that make
sense?
Anyway, The Scroll Art Museum has lots of them, and they’re much better than mine. I especially love the faux-parallax effect in Skulls and Hearts, created by a “background” repeating pattern being scrolled by a number of lines slightly off from its
repeat frequency while a foreground pattern with a different repeat frequency flies by. Give it a look!
I think of ElonStan420 standing in that exhibit hall, eyeing those cars with disdain because all that time, energy, care, and expression “doesn’t really matter”. Those hand-painted
pinstripes don’t make the car faster or cheaper. Chrome-plated everything doesn’t make it more efficient. No one is going to look under the hood anyway.
…
Don’t read the comments on HackerNews, Adam! (I say this, but I’ve yet to learn not to do so myself, when occasionally my writing escapes from my site and finds its way over there.)
But anyway, this is a fantastic piece about functionalism. Does it matter whether your website has redundant classes defined in the HTML? It renders the same anyway, and odds are good
that nobody will ever notice! I’m with Adam: yes, of course it can matter. It doesn’t have to, but coding is both a science and an art, and
art matters.
…
Should every website be the subject of maximal craft? No, of course not. But in a industry rife with KPI-obsessed, cookie-cutter, vibe-coded, careless slop, we could use
more lowriders.
I’ve grouped these four perspectives, but everything here is a spectrum. Depending on the context or day, you might find yourself at any point on the graph. And I’ve attempted to
describe each perspectively [sic] generously, because I don’t believe that any are inherently good or bad. I find myself switching between perspectives throughout the
day as I implement features, use tools, and read articles. A good team is probably made of members from all perspectives.
Which perspective resonates with you today? Do you also find yourself moving around the graph?
…
An interesting question from Sean McPherson. He sounds like he’s focussed on LLMs for software development, for which I’ve drifted around a little within the left-hand-side of the
graph. But perhaps right now, this morning, you could simplify my feelings like this:
My stance is that AI-assisted coding can be helpful (though the question remains open about whether it’s “worth
it”), so long as you’re not trying to do anything that you couldn’t do yourself, and you know how you’d go about doing it yourself. That is: it’s only useful to
accelerate tasks that are in your “known knowns” space.
As I’ve mentioned: the other week I had a coding AI help me with some code that interacted
with the Google Sheets API. I know exactly how I’d go about it, but that journey would have to start with re-learning the Google Sheets API, getting an API key and giving
it the appropriate permissions, and so on. That’s the kind of task that I’d be happy to outsource to a less-experienced programmer who I knew would bring a somewhat critical eye for
browsing StackOverflow, and then give them some pointers on what came back, so it’s a fine candidate for an AI to step in and give it a go. Plus: I’d be treating the output as “legacy
code” from the get-go, and (because the resulting tool was only for my personal use) I wasn’t too concerned with the kinds of security and accessibility considerations that GenAI can
often make a pig’s ear of. So I was able to palm off the task onto Claude Sonnet and get on with something else in the meantime.
If I wanted to do something completely outside of my wheelhouse: say – “write a program in Fortran to control a robot arm” – an AI wouldn’t be a great choice. Sure, I
could “vibe code” something like that, but I’d have no idea whether what it produced was any good! It wouldn’t even be useful as a springboard to learning how to do that, because I
don’t have the underlying fundamentals in robotics nor Fortran. I’d be producing AI slop in software form: the kind of thing that comes out when non-programmers assume that AI can
completely bridge the gap between their great business idea and a fully working app!
The latest episode of South Park kinda nailed parodying the unrealistic expectations that some folks
seem to put on generative AI: treating it as intelligent or as a friend is unhealthy and dangerous!
They’ll get a prototype that seems to do what you want, if you squint just right, but the hard part of software engineering isn’t making a barebones proof-of-concept! That’s the easy
bit! (That’s why AI can do it pretty well!) The hard bit is making it work all the time, every time; making it scale; making it safe to use; making it maintainable; making it
production-ready… etc.
But I do benefit from coding AI sometimes. GenAI’s good at summarisation, which in turn can make it good at relatively-quickly finding things in a sprawling
codebase where your explanation of those things is too-woolly to use a conventional regular expression search. It’s good at generating boilerplate that’s broadly-like examples its seen
before, which means it can usually be trusted to put together skeleton applications. It’s good at “guessing what comes next” – being, as it is, “fancy autocomplete” – which means it can
be helpful for prompting you for the right parameters for that rarely-used function or for speculating what you might be about to do with the well-named variable you just
created.
Solving problems with LLMs is like solving front-end problems with NPM: the “solution” comes through installing more and more things — adding more and more context, i.e. more and
more packages.
LLM: Problem? Add more context.
NPM: Problem? There’s a package for that.
…
As I’m typing this, I’m thinking of that image of the evolution of the Raptor engine, where it evolved in simplicity:
This stands in contrast to my working with LLMs, which often wants more and more context from me to get to a generative solution:
…
Jim Nielsen speaks to my experience, here. Because a programming LLM is simply taking inputs (all of your code, plus your prompt), transforming it through statistical analysis, and then
producing an output (replacement code), it struggles with refactoring for simplicity unless very-carefully controlled. “Vibe coding” is very much an exercise in adding hacks upon hacks…
like the increasingly-ludicrous epicycles introduced by proponents of geocentrism in its final centuries before the heliocentric model became fully accepted.
This mess used to be how many perfectly smart people imagined the movements of the planets. When observations proved it couldn’t be right, they’d just add more
complexity to catch the edge cases.
I don’t think that AIs are useless as a coding tool, and I’ve successfully used them to good effect on
several occasions. I’ve even tried “vibe coding”, about which I fully agree with Steve Krouse‘s observation that
“vibe code is legacy code”. Being able to knock out something temporary, throwaway, experimental, or for personal use only… while I work on
something else… is pretty liberating.
For example: I couldn’t remember my Google Sheets API and didn’t want to re-learn it from the sprawling documentation site, but wanted a quick personal tool to manipulate such a sheet
from a remote system. I was able to have an AI knock up what I needed while I cooked dinner for the kids, paying only enough attention to check-in on its work. Is it accessible? Is it
secure? Is it performant? Is it maintainable? I can’t answer any of those questions, and so as a professional software engineer I have to reasonably assume the answer to
all of them is “no”. But its only user is me, it does what I needed it to do, and I didn’t have to shift my focus from supervising children and a pan in order to throw it together!
Anyway: Jim hits the nail on the head here, as he so often does.
In my first few weeks at my new employer, my code contributions have added 218 lines of code, deleted 2,663. Only one of my PRs has resulted in
a net increase in the size of their codebases (by two lines).
I need to pick up the pace if I’m going to reach the ultimate goal of deleting ALL of the code within my lifetime. (That’s the ultimate aim, right?)
ArtificialCast is a lightweight, type-safe casting and transformation utility powered by large language models. It allows seamless conversion between strongly typed objects using
only type metadata, JSON schema inference, and prompt-driven reasoning.
Imagine a world where Convert.ChangeType() could transform entire object graphs, infer missing values, and adapt between unrelated types – without manual mapping or
boilerplate.
ArtificialCast makes that possible.
Features
Zero config – Just define your types.
Bidirectional casting – Cast any type to any other.
Schema-aware inference – Auto-generates JSON Schema for the target type.
LLM-powered transformation – Uses AI to “fill in the blanks” between input and output.
Testable & deterministic-ish – Works beautifully until it doesn’t.
…
As beautiful as it is disgusting, this C# is fully-functional and works exactly as described… and yet you really, really should never use it (which its author will tell you, too).
Casting is the process of transforming a variable of one type into one of another. So for example you might cast the number 3 into a string and get
"3" (though of course this isn’t the only possible result: "00000011" might also be a valid representation, depending on the circumstances1).
Casting between complex types defined by developers is harder and requires some work. Suppose you have a User model with attributes like “username”, “full name”, “hashed password”,
“email address” etc., and you want to convert your users into instances of a new model called Customer. Some of the attributes will be the same, some will be absent, and some will be…
different (e.g. perhaps a Customer has a “first name” and “last name” instead of a “full name”, and it’s probably implemented wrong to boot).
The correct approach is to implement a way to cast one as the other.
The very-definitely incorrect approach is to have an LLM convert the data for you. And that’s what this library provides.
…
ArtificialCast is a demonstration of what happens when overhyped AI ideas are implemented exactly as proposed – with no shortcuts, no mocking, and no jokes.
It is fully functional. It passes tests. It integrates into modern .NET workflows. And it is fundamentally unsafe.
This project exists because:
AI-generated “logic” is rapidly being treated as production-ready.
Investors are funding AI frameworks that operate entirely on structure and prompts.
Developers deserve to see what happens when you follow that philosophy to its logical conclusion.
ArtificialCast is the result.
It works. Until it doesn’t. And when it doesn’t, it fails in ways that look like success. That’s the danger.
…
I’ve played with AI in code a few times. There are some tasks it’s very good at, like summarising and explaining (when the developer before you didn’t leave a sufficiency of quality
comments). There are some tasks it can be okay at, with appropriate framing and support: like knowing its way around unfamiliar-to-you but well-documented APIs2.
But if you ask an AI to implement an entire product or even just a significant feature from scratch, unsupervised, you’re at risk of rapidly hitting the realm of Heisenbugs, security
vulnerabilities, and enormous redundancies.
This facetious example – of using AI as a universal typecasting engine – helps hammer that point home, and I love it.
Footnotes
1How to cast basic types isn’t entirely standardised: PHP infamously casts the string "0" as false when it’s coerced into a
boolean, which virtually no other programming language does, for example.
2 The other week, I had a GenAI help me write some code that writes to a Google Sheets
document, because I was fuzzy on the API and knew the AI would pick it up faster than me while I wrote the code “around” it.