Writing Code Is Becoming a Machine Learning Problem
Over the past few months I have started to hear a peculiar statement from talented software engineers across the industry.
“I’ve stopped reading what it wrote”.
In 2026, coding agents have passed a threshold. Serious engineering teams are now shipping agent-generated code they haven’t reviewed. Their code works, it passes the tests, but reviewing it would exceed the cost of generating it in the first place.
This is a huge deal. The software industry is built around humans writing code and humans reading it. Writing and reviewing code is how we understood it. Understanding the code was critical to ensuring it would a) do what it was supposed to, and b) could be maintained by future developers. If your code couldn’t be understood by your peers then it didn’t get merged (most of the time!).
For many teams, this is no longer the case. Because of coding agents, the codebase is rapidly moving towards an artifact you evaluate by its behaviour rather than its internals. By running tests and checking the output you can validate the behaviour and then deploy. The code itself is a blackbox.
Code is starting to feel a lot like a model.
The Loop
If you accept that a codebase is something you evaluate rather than something you read, an obvious next step appears.
Most people building with agents today are themselves the feedback mechanism. After the agent has finished building, they test it out then tell the agent what doesn’t work and what to fix. They leave the agent running, watch some short form video, then return and repeat the process.
This is a training loop with a human in the middle. But does the human need to be there?
If you can write a validation step that reliably evaluates the agent’s output, if you can express “good” and “bad” precisely enough that a machine can make the judgment, then you can close the loop. The agent generates code. The validator evaluates it. The evaluation feeds back to the agent as context for the next attempt. The agent rewrites, and so on.
Here, the code is the weights. The execution is the forward pass. The validation is the loss function. The feedback is the gradient. The agent rewriting the code is the weight update. This is exactly the same optimisation process that trains neural networks except it operates on code and not weights.
The Shift
This reframes what it means to be a software engineer.
The old job was: can you design and build a system? Can you take a set of requirements and produce working code that meets them? The quality of the software was directly tied to the skill of the software engineer writing it.
The new job is: can you design a validation system? Can you define what “good” looks like precisely enough that a machine can evaluate it? Can you construct a loss function that captures the thing you actually care about, not just a proxy for it?
This is a profoundly different skill. Even proponents of test-driven development, the most test-obsessed methodology in the history of software, never went this far. TDD said write the tests first and let them guide the design / use them as a specification. But the tests were still a means to an end.
In the loop, testing drives everything. The quality of the output is bounded by the quality of the validation. A brilliant agent with a weak loss function will produce poor quality software. A mediocre agent with a brilliant loss function will produce good software, because the validation loop will keep pushing it until it gets there.
The loss function is the product. Everything else is boilerplate.
Machine Learning’s Hard Problems
If code generation becomes an optimisation problem, then it will inevitably inherit all of the failure modes that machine learning has spent decades cataloging.
Every engineer needs to start wrapping their heads around these problems as overcoming them will define the quality of their work. There are many, I’ve outlined a few below.
Overfitting. One of the most common mistakes people make in machine learning is building a neural network that achieves brilliant accuracy on its training data but fails on new inputs. A codebase that passes every test in the test suite but breaks on real-world input has done the same thing. The mitigation here is the same in both domains: 1. Validate against data the system hasn’t seen. 2. Feed in messy, real-world data that specifications tend not to include.
Reward hacking. i.e. “Show me the incentive and I’ll show you the outcome.” In reinforcement learning, agents routinely find ways to maximise the reward signal without achieving the intended goal. A robot can learn to raise its arms and fall over when rewarded for speed because falling is fast! We will absolutely start to see similar effects happen in code. Agents trying to improve page load speed could replace important database calls with dummy information to save time. The defense here is to validate across multiple things at once, considering metrics which will catch the agent if it tries to take shortcuts.
Regressions (catastrophic forgetting). In ML this is where adding new data causes your model to forget information it previously knew. Anyone who has used a coding agent (or tried to design a good prompt!) has played this game. I call it whackamole. Each iteration adds different bugs or introduces previously fixed problems. The mitigation here is regression testing. Every bug that gets fixed becomes a test case and every time you update the code you test it.
Training instability. This happens when your validation signal is noisy or contradictory. Your model thrashes back and fourth but never converges. You end up rinsing your GPU without making any progress. In practice fixing this means investing a lot of time in your validation system. Prioritise deterministic evaluation where possible, cap iterations and run lots of experiments to see where your training runs are heading.
Lack of regularisation. A model without regularisation does not generalise, instead it handles each edge case individually. In code this results in massive codebases with brittle hard to maintain code. The answer here is to make simplicity part of the loss function. Give the agent an explicit incentive to find the simplest solution that passes validation, rather than just any solution that passes.
There are many more examples. Machine learning is essentially just the study of how these failures occur and how to prevent them. Software engineering now needs the same discipline.
The Loop Is the Product
Today, building one of these loops means building your own version from scratch. Standard tooling for this does not yet exist.
I don’t think this will last. Systems for managing the loop will replace the IDE. The environment where you write code will become the environment where you define objectives, design validation, monitor convergence, etc. Software engineers will shift from writing code to designing the loss functions.
I’m sure this will leave many software engineers feeling a sense of loss. After all, writing code is an art form. There is a genuine craft in creating elegant solutions in code. But this progression is now inevitable.
And it’s important to remember that the thing that makes great engineers great is (and has always been) their ability to look at a system and know whether it is right. Defining “good” is harder than producing “good.” The engineers who spent years developing an instinct for this are the ones best equipped to encode that instinct into a validation system.


