Every year or so a demo circulates in which a model builds a working application from a paragraph of description, and the conclusion is drawn that programming is finished. Every year, the number of people employed to write software has gone up.
Both observations are real. Reconciling them requires being specific about what the job consists of, because the part that got automated and the part that pays are not the same part.
What the job is actually made of
Ask a working engineer where their week went and the answer is rarely "typing code". A rough and widely recognisable breakdown:
- Working out what should be built, which usually means discovering that the request as stated is not quite what is wanted
- Reading existing code to understand why it does something strange
- Deciding how a change fits into a system that already has opinions
- Writing the change
- Working out why it does not behave as expected
- Reviewing other people's changes
- Deploying, monitoring, and being wrong about something in production
- Meetings, documentation, and negotiating priorities
Code generation is transformative for exactly one of these and helpful at the margins of three others. That is a real productivity gain. It is not the elimination of a profession.
Where the tools are genuinely strong
Be fair to them, because they are better than sceptics admit.
Boilerplate and glue. Serialisation, configuration, client libraries, the fourteenth CRUD endpoint. Work that is tedious precisely because it is predictable, which is what these models are best at.
Unfamiliar syntax. Writing correct code in a language you last touched in 2019, or a framework you learned yesterday. The model has effectively memorised the documentation.
Tests. Generating a broad set of cases against a described contract is a genuinely good use, particularly for the boring edge cases humans skip.
Explaining code you did not write. Point it at an intimidating function and ask what it does. This is one of the highest-value and least-discussed uses.
Mechanical refactors across many files. Rename, restructure, migrate an API. Tedious, well-defined, and easy to verify with a test suite.
Every strong case has a fast, honest feedback signal: the tests pass or they do not, the code compiles or it does not, the behaviour matches or it does not. Where verification is cheap, generation is valuable. Where verification is expensive, generation shifts work rather than removing it.
Where they still struggle
Understanding the system. Real codebases carry history. A function is odd because of a customer incident three years ago. A model reading a slice of the repository cannot know that, and will confidently simplify away the thing that was load-bearing.
Deciding what to build. Most requirements arrive underspecified and mildly contradictory. Resolving that means talking to people, understanding a business, and knowing which stated requirement will be quietly dropped once the trade-off is explained. None of that is in the repository.
Debugging genuinely hard problems. Not syntax errors — the race condition that shows up once a week, the memory growth under a particular load pattern, the bug that only appears on one customer's configuration. This requires forming hypotheses and running experiments against a live system.
Being accountable. When a deployment takes down payments, someone has to own it, understand it, fix it and explain it. Responsibility does not delegate to a model.
Long-range design. Choices about data models and boundaries are cheap now and expensive in three years. Getting them right is a judgement informed by having lived with the consequences of getting them wrong.
What actually changed about the work
The interesting effect is not fewer developers. It is a shift in where the difficulty lives.
| Was hard before | Is hard now |
|---|---|
| Producing the code | Reviewing the volume of code produced |
| Knowing the syntax | Knowing whether the approach is right |
| Writing tests at all | Writing tests that test something meaningful |
| Finding a code example | Judging whether the example fits your system |
| Typing speed | Reading speed and taste |
Review has become the bottleneck. It is now trivially easy to generate four hundred lines that look plausible, and reviewing four hundred plausible lines is genuinely harder than reviewing forty lines somebody thought about. Teams that have not noticed this are accumulating a specific kind of debt: code that works, that nobody understands, that nobody chose.
The honest risk, which is not "no jobs"
There is a real labour effect, and pretending otherwise is not useful. It falls unevenly.
The tasks most exposed are the ones that were both simple and verifiable: small isolated features, straightforward page implementation, routine integrations, basic scripting. Historically, that work was how people entered the industry. If the junior tier of tasks shrinks, the ladder gets harder to climb, and that is a structural problem the industry has not solved.
What is much less exposed is the work that requires holding a system in your head, talking to humans, and taking responsibility. Demand for that has not fallen. If anything, more code being written faster increases the need for people who can tell whether it should have been.
If you are learning to code now
The advice has changed in emphasis, not in substance.
- Learn to read code before you optimise for writing it. Reading is the skill with rising value.
- Get properly good at debugging. Reading stack traces, bisecting, forming hypotheses, using a profiler. This is the least automatable core skill.
- Understand the layer below. How memory, networks, databases and processes actually behave. Models produce code that is syntactically fine and architecturally naive, and you need to be able to tell.
- Never merge code you cannot explain. This is the single most important discipline. If you cannot describe why each part is there, you have not finished.
- Use the tools, deliberately. Refusing them is a handicap. Depending on them without review is worse.
- Build something end to end. Deploy it, watch it break, fix it. That loop teaches things no generated snippet can.
The realistic forecast
Software engineering is following the path of every other field that got a powerful tool. Spreadsheets did not eliminate accountants; they raised what an accountant was expected to produce and moved the skill from arithmetic to modelling. Compilers did not eliminate programmers; they moved the work up a level of abstraction.
Code generation is a further step up that same staircase. The output expectation rises, the tedium falls, the judgement becomes the job. The people who do well will be the ones who treat the model as a fast collaborator with no context and no accountability — useful for the part that was never the hard part.