Essays 8 min read

AI Development Revolution Part 7: Advanced Patterns

Advanced patterns from a game I built. Interfaces, metadata, batch operations, and what it takes to make code a machine can actually work in.

AI Development Revolution Part 7: Advanced Patterns

Advanced Patterns

Part 7 of the AI Development Revolution. The patterns here came out of one game, and I did not plan any of them.

A game taught me the rest

I went back through the repository for a small physics game I had built, expecting to clean it up. What I found instead was that the code had organized itself, over weeks of working alongside the machine, into shapes that made the machine useful. Not because I designed it that way. Because every shape that made the AI stumble eventually got rewritten until it stopped stumbling.

The game is simple to describe. You tilt the device, a ball rolls through a maze, obstacles get in the way. Underneath it there is a level system, a physics layer, difficulty that adjusts itself, and a test pass that runs on every level. The mechanics were never the interesting part. The way the code had to be built so an AI could help with it was.

I wrote in "Living Through the AI Revolution" that this shift changes how I think, not just how I build. This essay is the most concrete version of that I have.

Interfaces are how the machine finds its way

The first thing that mattered was interfaces. I had always treated them as good practice. Here they turned into something more useful: a map the AI could read without reading everything.

abstract class LevelManagerInterface {
  Future<void> initialize();
  Level get currentLevel;
  List<Level> get orderedLevels;
  // ... clear contracts for everything
}

When the AI needed to change the level system, it did not have to load the whole implementation into its head. It worked against the contract. That kept it focused and kept it from breaking things it had not read. Clear boundaries meant safe changes, even when I was moving fast and changing a lot. The interface was as much for the machine as for me.

Metadata is a layer you can move without breaking anything

Separating the data about a level from the level itself gave me a second handle. The AI could read and change properties without touching the actual implementation.

It could reorder levels by their calculated difficulty, scan for quality problems, write up a report, and update hundreds of levels in one pass, all by working on the metadata alone. None of that touched the code that ran the game, so none of it could corrupt it.

What had been slow manual work became something I could trust to run on its own. That part surprised me. I expected efficiency. I did not expect it to feel clean.

Testing the machine can run, not just pass

The tests changed too. They stopped being a checklist and started being the thing that let me make aggressive changes without fear.

The level system checks goal placement, pathfinding, the physics, and performance. Load times under 100ms. Frame rates above 60. Each test is a way for the AI to catch a problem I would have missed. It validates hundreds of levels at once, fixes the common problems itself, and flags the strange ones for me. I read the flagged ones. The rest I let it handle.

Difficulty that sorts itself out

I stopped assigning difficulty by hand. Instead the system calculates it from obstacle complexity, path length, physics, and time pressure, and lets each level find its own place in the order.

A weak level sinks in the rankings. A strong one rises. The AI makes decisions off those numbers, new levels slot themselves in where they belong, and the whole thing reorganizes when something changes. The balance comes out of the data instead of out of my gut, and for this kind of game my gut was wrong often enough that I was glad to hand it over.

Batches, because that is how the machine thinks

The AI works in batches. Once I noticed that, I built batch support into everything.

Validate a batch of levels, update difficulties in bulk, run a quality pass across all of them at once. Work that would have taken me hours finished in seconds, and stayed consistent across every change. The reason it worked was not just speed. The machine naturally handles sets rather than one thing at a time, and once the code matched that, the friction went away.

Workflows that assume the AI is there

I stopped bolting the AI onto the project and started assuming it from the beginning. There are agents that generate batches of levels with set parameters, agents that improve weak levels without wrecking the core of the gameplay, and tests that run continuously and catch regressions before they spread.

Every change kicks off validation. Performance is benchmarked without me asking. Quality is watched as a live number. I do not babysit it. I read what it surfaces.

Documentation written for a reader who is partly a machine

There is a CLAUDE.md in the repository, and it is not an afterthought. It is documentation written so the AI can act on it. The clean-architecture rules are stated plainly, the quality standards are given as numbers, the workflows are spelled out.

It ends up being a contract between what I mean and what the machine does. The file structure does the same thing in a quieter way: clear hierarchies, obvious purposes, so an agent can find what it needs without me steering every step.

Performance so the AI does not stall

The optimizations were not only about making the game fast. They were about keeping the AI's work from stalling. Lazy loading so an agent can read metadata without paying for the full data. Caching shaped around the access patterns the AI actually has. Background processing so nothing blocks.

The point is that AI speed needs infrastructure under it. If the data is hard to move through, the help slows to a crawl. Make it navigable and the help stays useful.

What the game taught me

A few things came out of this that I now reach for by default. Interfaces as a map. Metadata as a layer you can move safely. Tests as the thing that lets you change boldly. Batches because that is the machine's grain. Documentation written for the machine as much as for me.

None of it came from theory. It came from doing the work and noticing what made the AI useful and what made it useless. And it connected backward. The interface habit came from the infrastructure work in Part 3. The testing came from the quality obsession. The batch thinking came from the content pipeline in Part 4, where scale broke my assumptions. I just did not see the pattern until the game put it all in one place.

What it costs

I will not pretend this is free. Architecture this deliberate takes real setup, and most projects do not need it. Keeping documentation that serves both me and the machine roughly doubles the writing. The test infrastructure is an investment. Holding the traditional way and the AI way in your head at the same time has a cost of its own, and it is not small.

So the trade is the same one I keep coming back to across this whole series. The capability is real. So is the complexity that buys it. For this game it was worth it. For a throwaway script it would not be.

Where it leaves me

These patterns are not a forecast. They work right now, in code I have shipped. The thing I keep coming back to is that the architecture mattered more than the tools did. The interfaces, the tests, the batches, the documentation, those are what made the difference, not which model I happened to be using.

I wrote in "Vibe Coding with AI" and "The Multithreaded Mind" about what it feels like to work this way, fast and strange and not quite human-only anymore. This is the part of it I can point at. Build the code so the machine can move in it, and the two of you can make something neither of you would have alone. That is the whole series, really, in one game I almost threw away.


Series Navigation: