<?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>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>
