<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Paul Stamp</title>
    <description>The latest articles on DEV Community by Paul Stamp (@paulnonatomic).</description>
    <link>https://dev.to/paulnonatomic</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1042404%2Fecfbcd46-99c3-4b2a-b5f5-f43f8ccf2520.jpg</url>
      <title>DEV Community: Paul Stamp</title>
      <link>https://dev.to/paulnonatomic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/paulnonatomic"/>
    <language>en</language>
    <item>
      <title>The Reload Cost</title>
      <dc:creator>Paul Stamp</dc:creator>
      <pubDate>Tue, 26 May 2026 09:27:43 +0000</pubDate>
      <link>https://dev.to/paulnonatomic/the-reload-cost-5gch</link>
      <guid>https://dev.to/paulnonatomic/the-reload-cost-5gch</guid>
      <description>&lt;h1&gt;
  
  
  The Reload Cost
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Deep focus wasn't a virtue. It was a response to a cost that AI has quietly removed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The weather has turned, which in the UK counts as an event. I'm in the garden with a coffee and a book, and for once the book is winning. It's &lt;em&gt;The Only Way Is West&lt;/em&gt;, a walk along the Camino de Santiago, the better part of five hundred miles across northern Spain with everything you need carried on your back. I love this stuff. Travel writing, walking memoirs, long linear journeys with a start, a finish, and not much in between except the next step. I've always filed it under escapism. Sitting here in the sun, I'm starting to think it's more specific than that.&lt;/p&gt;

&lt;p&gt;Behind the book, quiet but never off, is the pull to work. I don't resent it. I like it, mostly. That constant urge to build and tinker is the thing that made me a software engineer in the first place, and it's the thing clients come back for. I'm a builder of digital doodads who always delivers. That reputation wasn't an accident and I'm not shy about it.&lt;/p&gt;

&lt;p&gt;But the urge comes with a watchful eye that never quite closes. It scans for new trends, curious technologies, the shiny thing two clicks away, and it leaves a trail. I have a long, slightly embarrassing spectrum of unfinished git repos, each one an experiment that reached the point where I understood the thing and then stopped, never quite becoming something worth sharing with the world. A graveyard, if you're feeling dramatic. A junk drawer, if you're being honest.&lt;/p&gt;

&lt;p&gt;Here is the part I keep circling. The walk on the page is the exact opposite of how I work. One path, one direction, west. You cannot flit on a pilgrimage. You cannot open six tabs and leave them humming. There is the road and the next step and the cathedral at the end, and the whole appeal is that you are doing precisely one thing with your whole self.&lt;/p&gt;

&lt;p&gt;I did this once for real. My brother Adam and I walked Hadrian's Wall, east from Bowness-on-Solway, wild camping the eighty-four miles to Wallsend, fifteen kilos on my back and eighteen on his. We set off in November, which was a decision. Cold, wet, the days so short we spent hours walking in the dark by headtorch, the world shrunk to the small bobbing circle of light in front of my boots. One afternoon we were low on water, soaked through and leaning into the wind, when we found a tap set into a wall. We were thrilled. It didn't work. We came round the next corner and there was a cafe, open and warm, and I am not exaggerating when I say the soup, crusty bread and hot coffee rearranged my understanding of luxury. That is what the narrowness does. Shrink the world to the next step and a bowl of soup becomes enormous. The scenery helped, the wall riding the hills with horses and sheep and cattle for company. But the thing I carried home wasn't the view. It was the quiet of having exactly one thing to do.&lt;/p&gt;

&lt;p&gt;On the approach to Carlisle we hit a flooded underpass, the path simply gone under a temporary lake. I still have the photo of Adam, bandana on, slumped at the edge of the water that had closed the path. I was scanning it for a way through like a bug newly surfaced in code review, turning it over, hunting the clean fix. We dreamed of a kayak washing up at the water's edge, the simple solution, but the November days were too short for dreams and wishes. So we went with brute force, hauling our combined thirty-three kilos of backache over gate after gate on a three-kilometre detour. In hindsight the lake was probably an overstated puddle and we should have waded it. No matter. I've made my peace with the fence; standing in the water weighing it up gets you nowhere, and the only move that counts is the one that goes forward.&lt;/p&gt;

&lt;p&gt;Even a flooded path has a direction. The desk doesn't. The quiet of one thing at a time is gone. There was a version of this job, and I had it for years, where you put the hood up, ran the coffee in intravenously, and held one problem in its entirety until it cracked. Tunnel vision as a virtue. Those days feel over. Client expectations shifted, my own shifted with them, and the lazy assumption that AI makes everything faster has eaten the time that used to be set aside for the long stare. Now I flit. Experiment, client build, experiment, a manic context-switching dance that puts more strain on my head than the work itself does. I've built tools to manage it. I've used other people's tools to manage it. Nothing has replaced my own mind as the thing actually doing the switching.&lt;/p&gt;

&lt;p&gt;There is one place the flitting stops, and that's the client work. It always gets finished. Partly for the obvious reasons, a happy client and a payday, but mostly for a less flattering and more reliable one. I have a superhero complex that drives me to overshoot every commitment I make. Under-promise, over-deliver. It's written into my harness, and I mean that fairly precisely. Every agent I run sits inside a harness, the scaffolding of instructions and tools that decides what it will and won't do. Turns out I'm running inside one too, biological rather than artificial, but a harness all the same, and somewhere inside it is a rule I didn't write and can't switch off. Do not quit.&lt;/p&gt;

&lt;p&gt;The wall proved it. Adam made it three days before the cold and the weight took its toll, and he caught the bus back to Carlisle. I carried on alone to the end. The last drag out of Newcastle to Wallsend isn't scenic, and everything in you wants to stop while the city is still wrapped around you, but the harness doesn't take requests. It's the same trait that finishes every client project, and it doesn't even need a client to fire. I've already caught myself pricing up a return, solo this time, three days instead of four and a half, overshooting a commitment I made to nobody but myself. A committed line and a person waiting at the end of it, a pilgrimage with the route already marked, and the harness will not let me arrive late or light. My experiments get no such person and no such route, so they wander off and lie down.&lt;/p&gt;

&lt;p&gt;Which leaves an uncomfortable reframe. For years I treated the flitting as a flaw, a discipline problem measured against the old ideal of the engineer who locks onto one thing. But that ideal had economics underneath it. Deep focus was the right strategy because picking work back up was expensive; reading unfamiliar code cost you an hour of reload every time you broke the trance. AI didn't make that ideal easier to reach. It pulled out the thing that made it the correct bet in the first place. When the reload cost collapses, the person who can hold six half-built things in loose orbit and drop into any one of them on demand isn't the scattered one anymore. They're the one &lt;a href="https://nonatomic.co.uk/blog/editorial-engineering" rel="noopener noreferrer"&gt;running the new machine&lt;/a&gt; the way it wants to be run.&lt;/p&gt;

&lt;p&gt;So the junk drawer isn't a confession. It's the inventory. The unfinished repos are exactly what you'd expect from someone whose real skill turned out to be breadth under switching rather than depth under focus. I spent a long time apologising for the wrong thing.&lt;/p&gt;

&lt;p&gt;And yet. I still booked the walk. I still want the wall. Something real lived in that single line across the moors in the dark, and I don't think it's nostalgia to miss it.&lt;/p&gt;

&lt;p&gt;Halfway along, the path climbs to Sycamore Gap, where for well over a century one tree stood alone in the dip between two crests, the wall pouring over the hills on either side like the spine of some land-bound sea serpent. Someone took a chainsaw to it one night, most probably for the social media views (idiots!). The place has the air of a shrine now, and it lowers the mood where the tree must once have lifted it. The businesses strung along the wall, half of them with a sycamore on the sign, are still absorbing the loss of a thing they'd built their name on, never owned, and could never have protected. As a one-man business I felt that one in the chest. You can lose the thing your whole identity leans on overnight, through no fault and no fix of your own, to someone else's idiot decision. It put my own small grievance back in its box. I lost a way of working to a shift in economics. They lost a living tree to vandals.&lt;/p&gt;

&lt;p&gt;The new mode is genuinely more powerful and I wouldn't trade it back, but I notice I now have to leave the postcode to find the kind of focus that used to be there at my own desk on a wet Tuesday. I worry, too, about whoever is coming up behind me, the apprentice who may never get the years of single-track work that taught me what focus feels like, and so may never recognise what the switching is standing in for.&lt;/p&gt;

&lt;p&gt;For now the sun is out, the coffee is good, and the man in the book is still walking west. One direction, one step. I'll get back to my fourteen open branches in a minute. Just not yet.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>focus</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Editorial Engineering</title>
      <dc:creator>Paul Stamp</dc:creator>
      <pubDate>Tue, 05 May 2026 11:22:46 +0000</pubDate>
      <link>https://dev.to/paulnonatomic/editorial-engineering-2onk</link>
      <guid>https://dev.to/paulnonatomic/editorial-engineering-2onk</guid>
      <description>&lt;p&gt;I was out walking with my dog Dexter, daydreaming on the first properly warm day of the year. I was lost in my own mind mulling over a conversation I'd had with a fellow Game Developer about how we've adapted to the use of AI as software engineers. None of the existing labels fit. "Vibe coding", Karpathy's term, elicits a culture of care-free one-shotting with little to no regard for the code quality, just keep prompting until it runs. "Agentic engineering" has also drifted toward a fire-and-forget autonomy, where you describe a goal, the agent disappears for an hour, and returns with a pull request you merge in the quiet hope that nobody asks you about it later. Neither description fit the experiences that my colleague and I were having.&lt;/p&gt;

&lt;p&gt;What we do is closer to editing, so to my mind the term editorial engineering seems a more appropriate fit, and here's why.&lt;/p&gt;

&lt;p&gt;Firstly, it's worth being clear about which kind of editing I mean. Not text editing, not the typing itself. Editorial editing, the kind a magazine or book editor does. Commissioning work, reading it, sending it back for revision, holding it to a standard, putting your name on the thing that finally ships.&lt;/p&gt;

&lt;p&gt;In practice that means I provide a detailed spec, or I talk through a problem until a spec emerges. I let the agent write code when the stakes allow it, when the implementation is well-trodden, or when I just want a first draft to react to. Then I read what it wrote. I push back. I ask why a particular approach was taken. I request refactors when something offends my taste or violates the standards a piece of code needs to meet. The bar for an internal tool and the bar for client-facing production code are not the same, and the agent doesn't intuit which one we're operating under unless I tell it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Editing is real work
&lt;/h2&gt;

&lt;p&gt;There's a sleight of hand in a lot of the AI discourse where delegation gets treated as savings. The thinking goes, the agent writes the code, so you save the time it would have taken to write it. That framing misses what editors actually do, and it misses why editorial roles in publishing have existed for centuries despite the writers being perfectly capable of typing.&lt;/p&gt;

&lt;p&gt;A good editor reads carefully. They notice what isn't there as much as what is. They push back on structure, on pacing, on the choice of one word over another. They hold the writer to the standards of the publication. A tabloid editor and a literary editor both edit, but to wildly different ends. And they are answerable for what gets published. If something ships that shouldn't have, the editor's name is on it as much as the writer's.&lt;/p&gt;

&lt;p&gt;Editorial engineering inherits all of that. Reading the code carefully. Noticing what isn't there. Pushing back on structure, on naming, on the choice of one pattern over another. Holding the agent's output to the standards of the project, and those standards genuinely vary. A personal prototype, a client production system, a public open-source package, and an internal tool all have different bars, and part of the editorial job is knowing which bar applies and enforcing it. And then answerability. The agent isn't going to defend its choices in a code review or a post-mortem. I am.&lt;/p&gt;

&lt;p&gt;The cost of this work is real, even when, like me, you are doing it on a phone whilst walking the tow-paths of the Macclesfield canal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading unfamiliar code is expensive
&lt;/h2&gt;

&lt;p&gt;This is the part that gets glossed over in most of the productivity claims. Reading unfamiliar code is genuinely cognitively expensive, and most developers have organised their careers around avoiding it.&lt;/p&gt;

&lt;p&gt;Ask any experienced developer about the worst projects they've worked on, and a large fraction will name the same kind of thing. Inheriting another dev's half-finished prototype. Picking up a codebase from a contractor who shipped and disappeared. A "small fix" on a system whose internal logic appears to have been copy and pasted from an ancient Stack Overflow post (remember Stack Overflow? it's seems crazy to ask). We hate this work because reading code written by someone whose taste, standards, and assumptions don't match your own is brutal. You aren't parsing syntax, you're reverse-engineering a mental model from the depths of another developers mind, and you then have to decide whether to adopt it, fight it, or quietly rewrite it. I'll happily charge a client more to turn a previous developer's spaghetti into a masterful bolognaise. The markup is honest because the cleanup is harder than writing every line from scratch.&lt;/p&gt;

&lt;p&gt;Editorial engineering shares the shape of all this. Every agent draft is code I didn't write, in a style averaged out of an entire training corpus, with idioms and structural choices that may or may not match how I'd have done it. The cost of reading and judging it is real, and it doesn't disappear just because the agent produced it in thirty seconds. If anything, the speed of generation makes it worse, because the volume of code I'm being asked to evaluate goes up.&lt;/p&gt;

&lt;p&gt;So no, this isn't less work than writing the code yourself. It is differently distributed work, and in some respects it's harder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the leverage actually comes from
&lt;/h2&gt;

&lt;p&gt;If editorial engineering isn't less work per task, the gain has to come from somewhere else, and it does. It comes from parallelisation.&lt;/p&gt;

&lt;p&gt;When I'm writing code myself I'm locked into one problem for the duration. One model of one system in working memory. The agent breaks that constraint. While one agent grinds on a Unity addressables refactor, another can be drafting middleware for a Next.js auth gate, and a third can be working through a spec for a multiplayer render-streaming architecture. The implementation work parallelises. The editorial work doesn't.&lt;/p&gt;

&lt;p&gt;This compounds on a skill professional software engineers already have, because the industry almost never lets us focus on a single thing. The myth of the engineer in the focus cave with their headphones on, building one thing for eight uninterrupted hours, is mostly a myth. What we actually do, and have always done, is context switch. We pick up a problem, load its model into working memory, make progress, drop it, load another, repeat. The good engineers aren't the ones who avoid context switching. They're the ones whose re-entry cost is low. The ones who can pick up a half-finished thread and be productive on it within minutes. Who keep their projects in a state where coming back is cheap. Who write notes, specs, and commit messages that future-them can rejoin without reconstructing the whole picture from scratch.&lt;/p&gt;

&lt;p&gt;That's the actual shift. Not "the AI does the work." The AI does the typing. The human does the editing, and the editing happens across the breadth of a project or portfolio of projects rather than a single task.&lt;/p&gt;

&lt;h2&gt;
  
  
  What gets left behind
&lt;/h2&gt;

&lt;p&gt;There are losses worth naming. I'll never again get to feel like I'm living through a hacking montage. Hood up, energy drinks within reach, cherry-browns clacking at pace, the screen full of code I'm pulling out of my own head in real time. That experience was a particular kind of joy, and editorial engineering doesn't include it. The agent does the typing, and the typing was part of the fun.&lt;/p&gt;

&lt;p&gt;There's a quieter loss too. I have a mental lexicon of syntax built up over a decade or so of writing code, the kind of fluency where you reach for a pattern and your fingers already know the shape of it. Most of that lexicon is now going to lie dormant. The patterns are still in my head, the muscle memory is still in my hands, but the agent gets there first and I'm reading rather than writing. Use it or lose it applies to programming languages the same as anything else, and I suspect a few years from now the fluency will be thinner than it is today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lending your name
&lt;/h2&gt;

&lt;p&gt;Whether any of this is still something to be proud of is a question I'd rather not duck. A clearly sheltered colleague of mine once told me I was one of the best engineers he knew and that compliment landed and stuck with me, the kind of thing you quietly carry around as part of how you think about yourself. Nowadays most of the keystrokes are an agent's, so what does that compliment refer to anymore?&lt;/p&gt;

&lt;p&gt;The editor analogy gets me through this question. A book editor's name goes on the masthead even though they didn't write a word of the text. They commissioned it, shaped it, pushed back, held it to a standard, signed off on it. The book that ships is a product of their judgement as much as the writer's. Nobody seriously asks whether the editor is allowed to be proud of the books they've shepherded into print.&lt;/p&gt;

&lt;p&gt;Editorial engineering is the same shape. The agent typed the code. I commissioned it, shaped it, pushed back, held it to a standard, signed off. What changes is what the pride is in. Not "I wrote every line." Something more like "I made every meaningful call about what got kept, and the thing that ships is good because of those calls." That's still worth being proud of. It's just a different thing to be proud of.&lt;/p&gt;

&lt;p&gt;So that's the term I'll be using. Editorial engineering. Not because the agent does the work, but because I do. And the work is editing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Postscript
&lt;/h2&gt;

&lt;p&gt;This article took shape across that walk, ten kilometres of trails in two and a half hours. The article was drafted and redrafted with an agent on my phone as we went. The freedoms were real. I wasn't at my desk, the sun was out, Dexter was happy, I covered ground I wouldn't have covered today otherwise.&lt;/p&gt;

&lt;p&gt;The cost was also real, and it wasn't quite the one I'd have predicted. Editorial engineering doesn't just give you time back, it raises the production expectation to match. Having left the desk, I felt the pull to use the time, so I did. Some part of my attention stayed with the prose taking shape on the screen rather than the trail under my feet. Distance dog walking, properly enjoyed, asks for full presence. I gave it about three quarters. Dexter had a better walk than the editor did. Both halves are the point.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>gamedev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your GitHub README Is Broken for UK Developers (and You Haven't Noticed)</title>
      <dc:creator>Paul Stamp</dc:creator>
      <pubDate>Mon, 27 Apr 2026 13:10:22 +0000</pubDate>
      <link>https://dev.to/paulnonatomic/your-github-readme-is-broken-for-uk-developers-and-you-havent-noticed-4ae8</link>
      <guid>https://dev.to/paulnonatomic/your-github-readme-is-broken-for-uk-developers-and-you-havent-noticed-4ae8</guid>
      <description>&lt;p&gt;If you maintain an open-source repo with a README full of screenshots, GIFs, or diagrams, there's a decent chance a chunk of your audience is staring at purple boxes where your content used to be. The images still exist. The URLs still resolve. Anyone in the UK who visits your project just can't see them.&lt;/p&gt;

&lt;p&gt;This is the Imgur UK block. It's been live since September 30th, 2025, and seven months in, most people hitting "upload" on Imgur still have no idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually happened
&lt;/h2&gt;

&lt;p&gt;The common assumption is this is a UK Online Safety Act story. Close, but not quite. The OSA is part of the backdrop, but the actual trigger was the ICO, the UK's data protection regulator. On 10th September 2025 they issued a notice of intent to fine MediaLab (Imgur's parent company) over its handling of children's data and age-assurance practices. Rather than comply, Imgur geo-blocked the UK a few weeks later.&lt;/p&gt;

&lt;p&gt;The distinction matters. MediaLab's other services, Kik for example, are still available in the UK. They implemented age assurance and complied. Imgur chose not to. The ICO has also confirmed that leaving the UK doesn't make the fine go away.&lt;/p&gt;

&lt;p&gt;So: commercial decision, not legal mandate. The result is the same either way. UK users get "Content not viewable in your region" where images used to be, and so far no other country has followed. UK-only for now, but the precedent is set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why nobody notices
&lt;/h2&gt;

&lt;p&gt;The block isn't really the problem. The asymmetry is.&lt;/p&gt;

&lt;p&gt;If you're a maintainer in the US, Germany, or Japan, your README looks exactly the same as it did last year. The images load fine. Nothing in your workflow tells you anything is wrong. You get the occasional issue filed, but broken README images don't stop anyone getting work done, so UK developers just quietly move on.&lt;/p&gt;

&lt;p&gt;Popular tooling makes it worse. ShareX, one of the most-used screenshot tools on Windows, still ships with Imgur as its default anonymous upload destination. Millions of screenshots get uploaded with muscle-memory keystrokes, pasted into GitHub issues and READMEs, and are invisible to UK audiences from the moment they land. No feedback loop, no warning, nothing.&lt;/p&gt;

&lt;p&gt;You get what you'd expect: a growing pile of broken content across open source, invisible to the people best placed to fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;I run &lt;a href="https://pkglnk.dev" rel="noopener noreferrer"&gt;pkglnk&lt;/a&gt;, a transparent Git proxy for Unity packages that gives authors install analytics. One useful side effect is that we already index README content for every package we track, so I ran a count.&lt;/p&gt;

&lt;p&gt;Across &lt;strong&gt;2,612 Unity packages&lt;/strong&gt;, &lt;strong&gt;55 (2.1%)&lt;/strong&gt; embed at least one Imgur-hosted image in their README. That's &lt;strong&gt;210 individual images&lt;/strong&gt; UK developers can't see when evaluating whether to use a package, out of 6,370 total README images across the dataset.&lt;/p&gt;

&lt;p&gt;2.1% sounds small until you weigh it by impact. The 50 affected repos I could pull star counts for have &lt;strong&gt;over 14,000 combined GitHub stars&lt;/strong&gt;. Five of them have more than 1,000 stars each. Eleven have more than 500. Over half are above 50. These aren't obscure hobby projects, they're toolbelt-staple Unity packages. &lt;code&gt;marijnz/unity-toolbar-extender&lt;/code&gt; (1.9k stars), &lt;code&gt;cakeslice/Outline-Effect&lt;/code&gt; (1.5k), &lt;code&gt;DanielEverland/ScriptableObject-Architecture&lt;/code&gt; (1k), and &lt;code&gt;asus4/tf-lite-unity-sample&lt;/code&gt; (~1k) are all affected. So is &lt;code&gt;keijiro/KinoAqua&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It gets worse when you look at distribution inside the affected set. For most of those packages, Imgur isn't one image among many, it's the dominant host. Several have &lt;em&gt;every single&lt;/em&gt; README image on Imgur, so their documentation is effectively blank to UK developers rather than partially broken. The worst single case has thirty Imgur-hosted images in one README.&lt;/p&gt;

&lt;p&gt;The detection catches Imgur URLs inside markdown image syntax, HTML &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags, and bare links GitHub auto-renders. Textual mentions don't count.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extrapolating, carefully
&lt;/h2&gt;

&lt;p&gt;I could extrapolate this to a GitHub-wide number. I'm not going to. Unity devs aren't representative of GitHub as a whole, they skew indie and hobbyist, sitting in the Reddit-adjacent communities where Imgur took hold. Enterprise Java, ML research, and infrastructure code probably use Imgur at very different rates, and my data can't tell you which way.&lt;/p&gt;

&lt;p&gt;What I'm comfortable saying is that small percentages of large ecosystems still add up. Even if the 2% rate holds across the wider Unity world of OpenUPM, the Asset Store, and GitHub's gamedev tag, we're looking at hundreds to low thousands of affected packages in Unity alone. Scale that reasoning to GitHub's full surface and the absolute count of broken READMEs across open source is easily in the tens of thousands, probably higher. The exact number is guesswork, the order of magnitude isn't.&lt;/p&gt;

&lt;p&gt;If you maintain data on another ecosystem, npm, PyPI, crates.io, Packagist, I'd love to see you run the same query. The only honest way to know is to measure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do about it
&lt;/h2&gt;

&lt;p&gt;Stop uploading documentation images to Imgur. It was always an odd choice for technical content (trusting a consumer image service with your project's visual integrity) and now it's actively bad.&lt;/p&gt;

&lt;p&gt;The replacement is free and already integrated. Drag-and-drop an image into any web editor for a README, issue, or PR, and GitHub uploads it to &lt;code&gt;github.com/user-attachments/&lt;/code&gt; and hands you a permalink. No third party, no geo-block risk, no account needed, no link rot when the host pivots. For anything that really belongs with the code, commit the image into a &lt;code&gt;/docs&lt;/code&gt; folder in the repo itself.&lt;/p&gt;

&lt;p&gt;For Unity packages specifically, use a &lt;code&gt;Readme~&lt;/code&gt; or &lt;code&gt;Documentation~&lt;/code&gt; folder. The trailing &lt;code&gt;~&lt;/code&gt; tells Unity's asset importer to skip the folder entirely, so your images don't generate &lt;code&gt;.meta&lt;/code&gt; files or show up in consumers' Project windows, but they're still committed to git and visible on GitHub. Same trick the official Unity packages use for their docs.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;.github/images/&lt;/code&gt; folder works just as well and is more portable. Unity ignores dotfolders by default, most package tooling does the same, and &lt;code&gt;.github&lt;/code&gt; is already the conventional home for repo-adjacent files like workflows and issue templates. If you ship packages across multiple ecosystems, that's probably your path of least resistance.&lt;/p&gt;

&lt;p&gt;If you use ShareX, change the default uploader. Point it at S3, something self-hosted, or an alternative like &lt;code&gt;imgbb&lt;/code&gt; or &lt;code&gt;postimages&lt;/code&gt; if you want Imgur-shaped convenience with better longevity.&lt;/p&gt;

&lt;p&gt;For years of old blog posts and READMEs full of dead Imgur links you can't face rewriting, there's a Chrome extension that proxies Imgur through DuckDuckGo's content proxy for UK users. Clever hack, but it's someone else's infrastructure. Fine as a stopgap, not a plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Link rot by policy
&lt;/h2&gt;

&lt;p&gt;Imgur isn't broken. The images exist. The URLs resolve. The infrastructure works fine. A chunk of the internet just can't see them because of a regulatory dispute that has nothing to do with the content itself.&lt;/p&gt;

&lt;p&gt;This is link rot by policy, not by technical failure. It's a relatively new failure mode, and Imgur won't be the last service to make the call. The economics of geoblocking against overlapping national compliance regimes favour the block over the compliance work, especially for services with thin margins and user-generated content.&lt;/p&gt;

&lt;p&gt;If you're writing docs meant to last, treat third-party image hosts the way you already treat external JavaScript CDNs. Minimise exposure, prefer first-party hosting, assume anything you don't control will eventually break.&lt;/p&gt;

&lt;p&gt;If you want to check your own project, open your README in an incognito window through a UK-based VPN. You might be surprised.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This analysis used pkglnk's Unity package dataset. If you maintain Unity packages and want install analytics without giving up your GitHub-hosted source of truth, pkglnk is at &lt;a href="https://pkglnk.dev" rel="noopener noreferrer"&gt;pkglnk.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>opensource</category>
      <category>unity3d</category>
      <category>programming</category>
    </item>
    <item>
      <title>ServiceKit V2 — The Async Service Locator for Unity</title>
      <dc:creator>Paul Stamp</dc:creator>
      <pubDate>Sat, 18 Apr 2026 10:21:06 +0000</pubDate>
      <link>https://dev.to/paulnonatomic/servicekit-v2-the-async-service-locator-for-unity-4840</link>
      <guid>https://dev.to/paulnonatomic/servicekit-v2-the-async-service-locator-for-unity-4840</guid>
      <description>&lt;p&gt;I just shipped V2 of &lt;a href="https://github.com/PaulNonatomic/ServiceKit" rel="noopener noreferrer"&gt;ServiceKit&lt;/a&gt;, my lightweight dependency management package for Unity. Before I get into what's new, I want to address the thing some of you are already typing into the comments: yes, ServiceKit is a service locator. On purpose. I think that's the right shape for Unity, and V2 is where I've stopped hedging about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a service locator, not a "proper" DI framework
&lt;/h2&gt;

&lt;p&gt;The "service locator is an anti-pattern" mantra largely comes from enterprise .NET, where you control object construction, processes are long-lived, and writing an installer for two hundred services is routine. Unity isn't that world. Unity instantiates your components for you, so &lt;em&gt;something&lt;/em&gt; has to do late-binding resolution regardless of what you call it. The heavyweight DI frameworks respond to that by adding more ceremony, not less. Contexts, scopes, installers, factories, binding chains. Adopting Zenject is a lifestyle decision. You don't use Zenject so much as restructure your project around it.&lt;/p&gt;

&lt;p&gt;Service locators are the opposite trade. Low friction, no framework imposed on the rest of your codebase, incremental. You can drop ServiceKit in to solve one pain point without rewriting everything around it.&lt;/p&gt;

&lt;p&gt;The two classic critiques of service locators are hidden dependencies and async timing. V2 is where I've tried to put both to bed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hidden dependencies, un-hidden
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;[InjectService]&lt;/code&gt; on fields surfaces the dependency graph at the class level. It's not quite a constructor signature, but it's visible to code review, tooling, and the new Roslyn analyzers. That covers most of the "you can't see what a class needs" complaint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IPlayerController&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ServiceKitBehaviour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IPlayerController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;InjectService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;IPlayerService&lt;/span&gt; &lt;span class="n"&gt;_playerService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;InjectService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;IAudioService&lt;/span&gt;  &lt;span class="n"&gt;_audioService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;InitializeService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_playerService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadPlayer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two compile-time analyzers ship in V2:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SK003&lt;/strong&gt; flags &lt;code&gt;[Service(typeof(IFoo))]&lt;/code&gt; attributes on classes that don't actually implement &lt;code&gt;IFoo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SK005&lt;/strong&gt; catches &lt;code&gt;ServiceKitBehaviour&lt;/code&gt; subclasses that forget &lt;code&gt;base.Awake()&lt;/code&gt;.
Both catch the kind of bug that's annoying to hunt down at runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Async resolution, the real headache fixed
&lt;/h2&gt;

&lt;p&gt;This is the one I'm most pleased with. The traditional service locator's real failure mode in Unity isn't philosophical, it's the timing problem. You ask for &lt;code&gt;IAudioService&lt;/code&gt; in &lt;code&gt;Awake&lt;/code&gt; on the wrong GameObject, it isn't registered yet, you get null, and you're debugging initialisation order for three hours.&lt;/p&gt;

&lt;p&gt;V2 resolves this cleanly. Field injection is a single await:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// V1&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_serviceKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithErrorHandling&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteWithCancellationAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// V2&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_serviceKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InjectAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destroyCancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And under the hood there's a new atomic 3-state resolution primitive that performs registration and readiness checks inside a single lock:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryResolveService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMyService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ServiceResolutionStatus.Ready&lt;/span&gt;
&lt;span class="c1"&gt;// ServiceResolutionStatus.RegisteredNotReady&lt;/span&gt;
&lt;span class="c1"&gt;// ServiceResolutionStatus.NotRegistered&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Previously, consumers had to check registration, then readiness, then fetch, giving the world three chances to change between steps. V2 closes that window.&lt;/p&gt;

&lt;p&gt;Alongside that: task forwarding in &lt;code&gt;GetServiceAsync&lt;/code&gt; now happens inside locks, double-registration is blocked with &lt;code&gt;Interlocked&lt;/code&gt; operations, and circular-dependency detection uses types rather than string comparison. Less likely to bite you in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generics out, attributes in
&lt;/h2&gt;

&lt;p&gt;The other big ergonomic change. V1 asked you to inherit from &lt;code&gt;ServiceKitBehaviour&amp;lt;T&amp;gt;&lt;/code&gt;, which got painful fast when your own classes needed generics too. V2 replaces that with a plain base class and an explicit attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// V1&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AudioManager&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ServiceKitBehaviour&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IAudioService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;IAudioService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// V2&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IAudioService&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AudioManager&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ServiceKitBehaviour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IAudioService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Registration intent is declarative instead of tangled in type parameters, and abstract base classes can keep their own generics without fighting ServiceKit's.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating from V1
&lt;/h2&gt;

&lt;p&gt;Mostly mechanical: drop the generic parameter on &lt;code&gt;ServiceKitBehaviour&lt;/code&gt;, add &lt;code&gt;[Service(typeof(IYourInterface))]&lt;/code&gt;, and replace builder chains with &lt;code&gt;InjectAsync(this, token)&lt;/code&gt;. The README has the full migration guide, including how to handle abstract base classes that mix ServiceKit generics with their own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Install via Package Manager → &lt;strong&gt;Add package from git URL&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://www.pkglnk.dev/servicekit.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repo and docs: &lt;a href="https://github.com/PaulNonatomic/ServiceKit" rel="noopener noreferrer"&gt;github.com/PaulNonatomic/ServiceKit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MIT licensed. Issues and PRs welcome. If you think I'm wrong about the locator vs DI trade-off, I want to hear it. V2 is the foundation I want to build on, so I'm happy to argue about it.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>gamedev</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
