Research · October 2026

The Great Inversion

Nearly 40 years of software engineering in reverse. How code went from cathedral to sketch, and what’s still left for us humans.

In 1988, as a teenager, I hung around and helped GIGATRON.

GIGATRON was a hardware startup in Germany that ran, quite literally, out of a living room. No job titles. We just showed up and built things. The hardware team made RAM expansion boards for the Amiga 500 and 1000, and I wrote the software that told customers whether their new memory actually worked: RAM-TEST. It walked the expansion RAM with alternating bit patterns and told you exactly which chip on the board had failed.

Almost forty years later I was digging through old backups and found traces of it. A binary here, a source fragment there. Just enough to recognize it. And just enough to make me realize how completely the job of writing software has flipped since then.

Back then, if you wanted documentation, a new API, or a new way of building things, you needed a plane ticket. I packed a bag for Amiga DevCon, walked the massive halls at CeBIT, and later sat in sessions at Lotusphere, SAPPHIRE, and SAP TechEd. You came home with a canvas bag full of 3.5-inch floppies, binder manuals, and pages of handwritten notes.

If your code crashed, there was no search bar. You stepped through it in your head, spent hours in a debugger, or called a friend late at night.

I’ve been going through my own archives lately: floppy images, old IDE workspaces, my GitHub repositories, and my SlideShare decks. What I see isn’t a steady improvement in tools. It’s a complete reversal of the relationship between the developer and the code.

Act I: Everything Lived in Your Head

Before the internet, code was built almost entirely inside the developer’s mind. Your reference library was the stack of books next to the CRT monitor.

Because information was scarce, knowledge ran deep. Writing a RAM test meant knowing the memory map, the chip layout on the board, and exactly how the 68000 behaved, from memory or from a binder. Every line was a direct, manual translation of what you wanted into what the machine would do. You were the architect, the bricklayer, and the compiler’s sanity check, all at once.

Act II: The Digital Scavenger

Then the web arrived, and conference keynotes turned into downloads. The job changed from inventing everything yourself to finding the right pieces and fitting them together.

My SlideShare account is a pretty good record of that era: 28 decks, most of them written so that someone else could find them and reuse them. I posted my SAP portal role-based navigation session from ASUG 2013, Building custom SAP Fiori apps using SAP Web IDE from SAP TechEd 2015, Connecting devices to IBM IoT via MQTT from IBM Insight 2015, and the World of Watson hands-on lab. My most-viewed deck is Connecting NEST via MQTT, with about 6,000 views. Those were people doing exactly what I was doing: looking for someone who had already solved their problem.

In between, I spent years in enterprise mobile, including SAP Mobile, where tight memory, short battery life, and offline sync forced you to write lean, disciplined code. When the compiler threw something cryptic, I searched Stack Overflow. When I needed a pattern, I cloned a GitHub repo. And I gave back what I could: SAP Fiori sample apps, Node-RED flows for IBM IoT, and a whole series of TJBot recipes.

It’s also how I taught. Every TechWednesday at Six Nations Polytechnic, we’d take a sample, wire up a Raspberry Pi or an ESP8266, and make it do something new. Find it, adapt it, connect it.

But through all of that, the human was still the engine. We went out into the world, gathered the pieces, brought them home, and soldered them into something that worked.

Act III: The Great Inversion

Today, that direction has completely reversed.

Large language models have read the open-source code, the docs, the conference decks (very likely including some of mine), and they write functions, scaffolds, and test suites in seconds. I no longer go out into the world to gather code. The code comes to me.

You can see the break in my own GitHub. Here are the repositories I created each year, forks excluded:

Repositories created per year
2014  █████                                      5
2015  █████████████████                         17
2016  ██████████                                10
2017  ███████████████████                       19
2018  ██████                                     6
2019  ███████                                    7
2020  █████████                                  9
2021  ██                                         2
2022  ████                                       4
2023  ███                                        3
2024                                             0
2025  █                                          1
2026  ████████████████████████████████████████  40  (January–September)

In the first nine months of 2026 I created more repositories than in the previous eight years combined. I know a repo count is a crude measure, so look at what’s inside. My open-source Code Engine MCP server is on npm, the VS Code Marketplace, and the MCP Registry. My Zendesk MCP server ships to both npm and PyPI. ESP32-Traffic-Paxcounter is on firmware version 4. There’s even an Alexa skill that tells the time with a line from a book. I didn’t suddenly get more hours in the day. The cost of turning an idea into working code collapsed.

And my role flipped with it:

ThenNow
WorkflowSearch the world → write code → testAI writes code → I test → a second model reviews → I tune the prompt
My roleBuilder and syntax writerTest bench, runtime, and edge-case hunter
DirectionPulling knowledge inChecking generated output
CodeA cathedral: precious, guarded, refactoredA sketch: cheap, disposable, regenerated
What mattersKnowing the syntaxClear prompts, good tests, and knowing what “working” really means

Today I’m basically the AI’s real-world runtime. It proposes the code. I run it, have a second model review it, catch the made-up parameters and the security holes, paste the error logs back in, and go around again until it actually works.

What a bug looked like, then and now

The easiest way to show the flip is with the bugs themselves.

1988: one missing character. On the Amiga, you wrote code in a plain text editor, compiled it, and rebooted to test it. No red squiggles, no autocomplete. RAM-TEST itself was written in assembly, but here’s the same kind of mistake in C (a reconstruction, not the original source):

/* check the A500 trapdoor RAM, 512 KB starting at $C00000 */
#define PATTERN 0xAAAAAAAAUL
#define WORDS   0x20000L              /* 131,072 longwords */

unsigned long *ram = (unsigned long *)0xC00000;
long i;

for (i = 0; i < WORDS; i++)
    ram[i] = PATTERN;                 /* write the pattern */

for (i = 0; i < WORDS; i++) {
    if (ram[i] = PATTERN)             /* BUG: '=' should be '==' */
        continue;                     /* looks fine, next word */
    report_bad_chip(i);
}

One missing =. Instead of comparing each memory cell to the pattern, the code writes the pattern into it, and the result is always true. The compiler was perfectly happy. The program runs, and every chip passes, including the broken ones. Finding that meant printing the listing, stepping through it in your head, and going around the edit, compile, reboot, retest cycle again and again.

And when a mistake was really bad, you didn’t get an error message. You got this:

Software Failure.    Press left mouse button to continue.
         Guru Meditation #00000004.0000AAC0

2015: the IDE catches the typos. By the time I was building SAP Fiori apps in JavaScript, a mistake like that took seconds to fix. SAP Web IDE, and later VS Code with a linter, underlined it while I was still typing:

webapp/controller/Main.controller.js
   9:62  error  Missing semicolon                               semi
  14:13  error  Unexpected assignment within an 'if' statement  no-cond-assign
  17:21  error  'oModle' is not defined                         no-undef

The kind of bug that could eat an evening in 1988 now got a red underline before I had finished typing the line.

The hard bugs had moved to runtime. Things like Uncaught TypeError: Cannot read property 'getModel' of undefined, followed by a trip to Stack Overflow to find out why.

In between: a staircase, then a cliff. For about thirty years, every new tool made me a faster writer of code. IDEs caught my typos. Frameworks like Bootstrap and SAPUI5 handed me the skeleton. And Node-RED took IoT prototyping to a whole new level: instead of writing drivers and MQTT plumbing, you wired a few nodes together and had a working demo in an afternoon. That’s how I built most of my IoT demos, and why I shared a Node-RED starter for Bluemix so others could skip the setup too.

But all of those tools had one thing in common: I was still the author. Then, in just a few years, AI went from suggesting my next line to writing, running, and fixing the whole thing. Every earlier step helped me write the code. This one writes it for me. That’s not another step on the staircase. That’s the inversion.

2026: I barely look at the syntax. Today the thing I actually write is the prompt. For the ferry counter, it looks something like this:

Add direction detection to the dual-LiDAR counter.
A car joining the ferry lineup breaks beam B first, then beam A.
Ignore anything that blocks a beam for less than 40 ms (rain, birds).
Never block the LoRaWAN send loop.
Write tests for: a car joining, a car leaving, a person walking
through, and a car that stops halfway between the beams.

That prompt is the real source code now. The lines that matter aren’t syntax. They’re the details only someone who has stood at that roadside knows: the rain, the birds, and the car that stops between the beams because the lineup is full.

Then I run the tests, and I have a second model review the first model’s work:

test_car_joining .............. PASS
test_car_leaving .............. PASS
test_pedestrian ............... PASS
test_car_stops_between_beams .. FAIL  expected count=1, got 2

Review (second model): the state machine returns to ST_IDLE on a
timeout while beam B is still blocked, so the same car is counted
again when it drives off. Stay in WAIT_CLEAR until both beams clear.

One machine wrote the code, a different machine explained the bug, and my job was knowing that a car stopping between the beams is a real case worth testing. I haven’t hunted a missing semicolon in months. What I care about now is the prompt, the tests, and whether a second opinion agrees.

Code Is No Longer Precious

This was the hardest part for me to accept: code is no longer an asset you protect.

For most of my career, code was a cathedral. I never threw RAM-TEST away. I rewrote it, version after version, because every version had cost real effort. Deleting a week of manual refactoring felt like burning money.

Today, when an AI-generated version goes off track, I don’t spend hours debugging it line by line. I delete it and start over. Rebuilding takes minutes, not weeks.

My GitHub has a small monument to this. On February 27, 2026, I created wxo-toolkit-vsc, a VS Code extension for IBM watsonx Orchestrate. Three days later I marked it deprecated and replaced it with a cleaner rebuild: WxO-ToolBox-vsc. In 1988, abandoning a working tool after three days would have been unthinkable. In 2026, it was simply the fastest way to the better version.

The important part: deleting the code didn’t delete the progress. The first version was an experiment, and it left me with what I call tester’s knowledge: I now knew the edge cases, the API quirks, and the places where my first idea was wrong. I kept the learnings, threw away the syntax, and asked for a cleaner build.

+-------------------------------------------------------------------+
|                  THE EPHEMERAL FEEDBACK LOOP                      |
+-------------------------------------------------------------------+
|  1. Prompt Intent  -->  AI Generates Draft Code                   |
|  2. Human Tests    -->  Exposes Edge Cases & Invalid Code         |
|  3. Cross-Check    -->  A Second AI Model Reviews the Code        |
|  4. Nuke Code      -->  Retain "Tester's Knowledge" (Learnings)   |
|  5. Re-Prompt      -->  Generate Production-Grade Architecture    |
+-------------------------------------------------------------------+

Act IV: Where the Machine Still Needs Us

So if the AI writes the code and we test it, what’s next?

I think we’re hitting the limits of plain code generation. These models are great at patterns they’ve seen before. They struggle with physical hardware, messy real-world signals, and closed platforms they can’t look inside.

Closed platforms: I’ve seen this movie before

In 2014 I got Google Glass before most people had heard of it. I built apps for it: a stopwatch, some work tools, and a LiveCard that sent MQTT messages to the IBM IoT cloud. I biked with it and ran with it. My honest field notes: voice commands don’t work in the wind, it rebooted a few times, and my Garmin still won.

But the hardware wasn’t what held Glass back. The platform was: gated APIs, approval friction, and very little room to hack under the hood.

AI can go the same way. If it stays locked inside closed, black-box products, developers become passive prompt-checkers. If it’s built on open standards like the Model Context Protocol (MCP), open models, and runtimes you can inspect, developers stay the architects.

That’s why so much of my 2026 has gone into MCP. I built and open-sourced MCP servers for IBM Maximo, IBM Cloud Code Engine, and Zendesk, because I wanted them to exist. They’re personal projects, not IBM products. And I made the case for MCP as a platform at the Linux Foundation MCP Dev Summit. Glass taught me what a closed platform costs developers. MCP is the opposite bet.

The physical world doesn’t care how plausible your code looks

I learned this one the hard way, long before AI. In 2016 I automated my entire house: LIFX bulbs, the Nest, a Raspberry Pi, Node-RED, all running through Bluemix. I even ripped out the kitchen light switches. Then the internet went down while I was away on a business trip, and my wife couldn’t turn on the lights. You can imagine the call I received. I had to un-automate everything, and I wrote about it publicly under the title “Can too much automation lead to divorce?”. I probably should have left the light switches in place.

The lesson stuck: the real world is where clever software goes to get humbled. And it’s exactly where AI-generated code struggles most.

I’ve spent years at that edge, from tracking animals with LoRaWAN to decrypting LoRaWAN packets in Node-RED. Today it’s ESP32-Traffic-Paxcounter, which uses two LiDAR sensors on an ESP32 to count cars, estimate their speed and length, and predict the ferry lineup, and FerryLight, a real-time tracker for the Englishtown ↔ Jersey Cove cable ferry in Cape Breton, Nova Scotia. People in the community check it before they drive to the ferry.

An LLM can make up a function and still pass a mock test. On the side of a road in Cape Breton, timing interrupts, electrical noise, and dropped LoRaWAN packets don’t care how plausible the code looks. A car either broke both laser beams in the right order or it didn’t. Somebody has to stand there and check. That’s still us.

I saw this coming a while ago. At HackMIT 2023, the challenge I set for the students was to connect generative AI to the real world. Three years later, that’s where the interesting problems are.

What’s Left for Us

Looking back nearly forty years, the friction of typing syntax has all but vanished. The need for real engineering judgment hasn’t. If anything, it matters more.

I started with a RAM test on an Amiga in a living room. I went through binders and floppies, enterprise mobile, and years of scavenging on SlideShare and GitHub. Today I mostly judge code a machine wrote. What I never handed over is deciding what’s worth building, and whether it really works when a real car drives past a real sensor.

Full disclosure: AI helped me draft this article. I checked every fact against my own repositories and decks, which is kind of the point.

If you’ve been writing code long enough to have your own RAM-TEST in a box somewhere, I’d love to hear what your inversion looked like. And if you’re about to delete your first AI-generated prototype: go ahead. Keep the learnings.

Cheers,
Markus

No bug 🐛 too small, no syntax too weird 🔍 🤔 🔨 🦾