When AI Writes the Code, a Developer's Real Skills Show
Only when the tide goes out do you discover who's been swimming naked

This post is about how the developer role is changing in the AI era, and what to do about it. It’s something I hear a lot at work lately - and honestly, it’s not just developers. Most knowledge workers seem to be sitting with the same anxiety.
The feeling tends to be equal parts excitement about what AI can do for productivity, and unease about what it might do to jobs.
Nobody knows how this actually plays out, and I’m no exception. But doing nothing feels worse. So here’s how I’ve been thinking about it.
Three years since ChatGPT
When ChatGPT launched in late 2022, I genuinely didn’t expect it to move this fast. There were constant hallucination problems, and the output quality wasn’t particularly impressive.
Three years later, a significant chunk of how I spend my day has changed.
The job used to be something like: understand what people need, design a solution, write code until it exists. You’d take requirements written in natural language, think through the design, and translate all of it into code by hand.
Not long ago, my morning started with opening an editor and placing the cursor in a blank file. Now it’s more like: explain the context to an AI, read what comes back, ask again, adjust, repeat.
I’ve been through the shift from feature phones to smartphones - that already felt fast. This is faster.
AI coding agents have been well past “basic autocomplete” for a while now. Give them a clear prompt and they’ll produce a function or module that’s hard to distinguish from what a developer would write. In this environment, writing every line yourself is becoming inefficient for at least some categories of work.
Things will probably keep accelerating. How the developer role reshapes itself will depend on the team and the context. The question is what to focus on now.
From code writer to decision-maker
To answer that, it helps to look at where the time goes. Time used to go into typing. Now it goes into prompting, reading generated output, adjusting, and prompting again.
Building software is shifting from direct code authorship toward something more like judgment - not just checking whether the AI did what you asked, but verifying that the business intent actually made it through to the technical implementation.
You could argue that as AI improves, even code review will be automated away. I don’t think so, and the reason isn’t about technical capability.
Someone has to be accountable for the code
A lot of developers are already using AI for code review - it reads the PR and leaves comments. Honestly, some of those comments are pretty sharp. It catches things I’d miss.
But I think there’ll always be a human who needs to put the final stamp on “this is okay to ship.” The reason comes down to one question.
When the code causes a problem, who is responsible?
AI is not a legal entity. It cannot be held accountable. So when AI-generated code breaks something, the question of who answers for it becomes urgent.
Say AI-written code has a bug in the payment logic that charges customers the wrong amount. What happens if the company responds like this:
"It was written by AI, so honestly, I have no idea why this happened."
No customer is going to accept that. Put yourself on the receiving end and it’s infuriating.
No matter who wrote the code, someone is accountable. The way I see it, that’s the developer who reviewed and approved it, and the organization they work for.
This isn’t just speculation - it’s already showing up in regulation.
The EU AI Act, which took effect in 2024, mandates human oversight of AI systems in high-risk areas like healthcare, finance, and infrastructure. The principle is clear: even when AI makes the call, humans must be able to review the process. It’s now law.
There are also ongoing discussions in the EU about extending product liability frameworks to digital products and software. “AI made it, not us” is becoming a harder argument to make legally.
Real-world precedents outside software point the same direction. When autonomous vehicles crash, liability goes to the manufacturer and driver. FDA-approved AI diagnostic tools still require a physician to make the final call. The 2010 Flash Crash, where algorithmic trading caused a cascading market collapse, showed that whoever runs the automated system is who the regulators come after.
The more automation you add, the sharper the line gets between the human in the loop and the consequences of what that loop produces.
So I don’t think the developer role disappears. It shifts from writing code to reviewing and approving it. The method of producing code has changed. What hasn’t changed is that the quality of the final product depends on whoever reviews it. So what does that actually require?
What AI-era development actually demands
The obvious guess is that prompt engineering or AI tool fluency becomes the key skill. I think that’s wrong.
You can now tell an AI “write this like Martin Fowler would” and get something that looks reasonable. But so can everyone else who types that sentence. What’s the edge there?
The real skill is knowing when the output doesn’t meet the bar - even when the prompt was supposedly good. Good prompts don’t guarantee good code.
Ironically, the skills that matter in the AI era aren’t that different from what has always separated good developers from average ones.
Because review still requires checking: will this break at runtime? Is it maintainable six months from now? Are there missing error cases? Does it violate any policies? And as long as a human is the one signing off, code still needs to be readable by humans.
If humans never needed to read code, we could ship bytecode. But you’re the one who has to answer when something breaks. Can you really approve a deploy without reading what you’re shipping?
As long as that accountability constraint holds, the questions developers think about today - what makes code readable, what makes it maintainable - will remain relevant.
Predicting the long-term cost of change
Scroll through LinkedIn lately and you see a pattern. A year ago it was “look what I built with AI in a weekend.” Now it’s occasionally “hired developers because we couldn’t maintain it” or “shut it down because we couldn’t add features.” Both kinds of posts are real.
This happens because AI is optimized for working code. It reproduces the patterns that appear most often in training data. Those patterns are, by definition, code that runs. Code that runs and code that’s easy to maintain six months later are two different things.
Newer models are getting better at factoring in maintainability. But that’s not quite the point. Output quality and predicting the long-term cost of change are separate problems.
Software quality doesn’t reveal itself immediately. The cost of a bad design shows up when you have to change the code, not when you write it.
Evaluating code from multiple angles
This was true before AI too. The difference now is that generation speed has increased, so deferred costs accumulate faster.
Review covers multiple dimensions. Functional correctness - does it do the right thing - is the part tests can catch. The harder part is structural quality.
Is this module’s responsibility scoped correctly? Is the dependency direction right? Is this interface flexible enough for future changes? Tests don’t answer these. Then there’s performance: the code works, but does it hold up when data volume is 10x? And security: is input validation sufficient, or is there a missing authorization check somewhere?
Evaluating code across all of these dimensions at once is a different skill from just reading code.
And as generation speed increases, this gets harder.
When developers wrote everything by hand, there was a physical ceiling on output. A developer can only type so much in a day, so the volume of code the team needed to review was naturally paced. Writing slowly doesn’t make code better - but it does mean production couldn’t easily outpace review capacity.
When AI can generate hundreds of lines in seconds, that balance breaks easily. Without solid review standards, parallel review processes, and automated gates, you can double or triple code volume while review capacity stays flat. Things start slipping through. Technical debt accumulates faster. The production line sped up but the quality control process didn’t.
My guess is this explains why many companies adopt AI and still don’t feel more productive. Code production got faster; review became the bottleneck.
In this structure, developers who can review code well and quickly become more valuable. The more code AI generates, the more you need someone who can filter out the hidden risks and bad abstractions mixed into that output.
Abstraction
Abstraction is another one. At its core, abstraction means deciding what to hide and what to expose in a complex system - where to draw the lines.
AI can do abstraction. It defines interfaces, divides classes, separates modules. Formally speaking, it sometimes does this better than I would. But there’s a key difference between AI abstraction and what an experienced developer produces.
AI abstraction is based on statistical averages from training data. It takes patterns that looked plausible across thousands of projects and applies whichever one fits closest. But real software design isn’t a multiple-choice test. It’s a series of tradeoff decisions made under resource constraints and uncertainty about the future.
AI can maintain internal consistency in code. What it struggles with is factoring in external context - the stuff that lives outside the codebase - when deciding where to draw the lines. Code that’s optimal for a specific situation requires strategic judgment that goes beyond statistical norms.
This isn’t really a flaw in AI - it’s a structural limit of statistical learning. You can produce code that’s good on average. Code that’s optimal for your specific situation is a different problem.
The dangerous thing about AI-generated code is that it looks fine. Files are properly separated, naming follows convention, patterns are familiar. It passes review easily.
The problem shows up later. You try to add a payment method and realize the “cleanly separated” structure requires changes in five different places simultaneously. This kind of defect doesn’t appear when you write the code. It appears when you try to change it.
AI-generated code shows this pattern fairly often. The structure follows common conventions perfectly, but it doesn’t quite fit the actual requirements.
A frontend example: ask AI to build a dashboard component and it typically produces one giant component with data fetching, state management, and UI rendering all mixed together. Or it over-applies best practices from training data and builds three custom hooks and a context provider just to render a single chart.
One is under-abstracted, one is over-abstracted. Both are wrong in the same way: neither fits the actual complexity level of the project. Good abstraction means creating exactly as much structure as the current situation requires. Knowing how much that is requires knowing the context.
An experienced developer reads this code, recognizes that the boundaries were drawn without understanding the domain, and redraws them. What that takes isn’t coding skill. It’s understanding of the system and a sense of design.
The same standard applies whether a human or AI wrote the code: is this abstraction actually reducing complexity, or just adding more indirection to track? Being able to ask that question is already a skill.
Articulating tacit knowledge
If abstraction is knowing where to draw the lines, articulating tacit knowledge is being able to explain why the lines go there. Related, but different. In practice they work together.
The instinct for recognizing bad code builds up gradually through reading and writing a lot of code. It usually starts as “something feels off” - tacit knowledge that’s genuinely hard to put into words.
Translating that instinct into language matters more now. “Something feels off” needs to become “this function has two responsibilities” or “this interface will break under change” - concrete enough to actually direct an AI.
This isn’t about prompt tricks like few-shot examples or chain-of-thought formatting. Those get absorbed into the model as it improves. What I’m talking about is the underlying ability: clearly defining what needs to be built, and knowing which context matters enough to include.
Anyone can say “build me this thing.” What matters is being able to identify exactly what’s wrong with what comes back, and explain specifically why it should be built differently.
Seeing “something wrong” code and knowing concretely what that something is - that’s design competence. The deeper your understanding of the system, the more precise your instructions to AI can be.
You don’t manipulate memory directly anymore, but you still need to understand the memory model to debug performance problems. You may not write every line of code, but you still need to understand abstraction to catch design problems. There’s an extra layer of indirection; the underlying need hasn’t gone away.
These skills have a longer shelf life than tool fluency. Tool fluency expires when the tool does. jQuery gave way to React. Webpack gave way to Vite. Design judgment and the ability to articulate tacit knowledge are valid as long as software has essential complexity - which is to say, indefinitely.
That complexity doesn’t disappear when the tools change. Payment systems are complicated because payments are complicated, not because of the framework. The instinct for handling that complexity doesn’t belong to any particular tool.
The need for deliberate practice
A reasonable question at this point: if you’re writing less code, how do you build abstraction sense and design instinct?
There’s a real tension here. You’re told to focus on what AI can’t do, while AI is quietly reducing the opportunities to practice those exact things.
The answer has two parts. One is protecting two specific points in your daily workflow from AI. The other is deliberately maintaining design instinct outside of work. And there’s a single attitude that runs through both.
Two points to keep for yourself: design and review
In a normal workday, there are two points not to hand off to AI: design before writing code, and review after.
Doing design yourself isn’t just a habit thing. If you define “what interface does this module expose?” and “where do the responsibilities end?” before you prompt, you can compare what AI produces against your own design decision.
If AI chose a different structure, you end up analyzing why. Did it catch something you missed? Or did it get it wrong? Without this step, you’re likely just consuming output. Consuming output and evaluating output against your own judgment are completely different experiences.
Review is the other one - and unlike deliberate practice, it shows up automatically in your workflow. Which is exactly why letting it slip is so dangerous.
Delegating PR review to AI and approving with no objections is like going to PE class and sitting on the bench for the whole period. The work gets done somehow, but several years of this and your skills haven’t moved.
Code review means reading code while holding requirements, design intent, and business context in your head at the same time. That process is the training.
Time to build things yourself
Doing your own design and review at work isn’t enough on its own. Design instinct requires knowing the pain of implementation.
You need to have personally experienced a structure falling apart under change before you can feel “this abstraction is wrong.” Pain you haven’t felt doesn’t become instinct.
Junior developers especially. Reviewing AI-generated code without much experience is a bit like asking someone still learning to drive to evaluate a self-driving car’s decisions. You get a feel for the road by gripping the wheel. You get a feel for structure by writing the code.
My guess is that for future developers, coding directly won’t be a daily job requirement - it’ll be more like ongoing training to maintain your judgment. (Maybe the painful grind of building things from scratch as a junior becomes less of a job requirement and more of a certification process - how you earn the right to be trusted as a reviewer.)
So in side projects and personal learning, I think it’s worth deliberately putting AI aside and building things end-to-end yourself. The more convenient AI gets, the more annoying that friction feels. But the friction is the point.
The moments where you get stuck, or where you realize you need to refactor - those are where the learning actually happens.
The attitude that runs through both: putting “why” into words
Whether you’re doing design and review at work, or building things alone in your own time, one attitude needs to run through both.
When “something feels off” shows up, don’t let it slide. Stay with it until you can say clearly what’s actually wrong.
Stopping at “feels off” is just a feeling. Getting to “this function has two responsibilities” is language. A feeling only you know. Language is usable. Once it’s language, you can direct AI precisely, explain it to teammates, and recognize the pattern when you see it again.
When AI produces code that works, don’t stop there. Ask yourself: why did it choose this structure? What tradeoffs would a different approach have had?
The gap between developers who ask this and developers who don’t will keep widening.
The fundamentals haven’t changed
AI is moving the developer role from code author to reviewer. We’re moving from humans doing both production and quality control, to AI handling production and humans handling quality control.
Understanding that this shift is driven by accountability - a social and legal constraint, not a technical one - makes the role change clearer.
Stamping “approved” well requires an eye for the difference between working code and durable code, the design sense to evaluate abstraction in context, and the ability to put that sense into words and steer accordingly.
The edge in the AI era isn’t about who generates more. It’s about who understands context well enough to approve responsibly. Developers are still accountable for code quality. That hasn’t changed.
AI is genuinely different from previous tools. Unlike a plow or a compiler, it reasons and generates. “It’s just another tool” isn’t a convincing argument anymore. So why would the required skills stay the same?
Start with accountability. Being accountable means making judgments. The quality of those judgments comes from being able to read structural health in code, distinguish abstraction that fits the domain from abstraction that doesn’t, and anticipate the long-term cost of change. These are the things that have always separated good developers from average ones.
Fred Brooks, in 1986, separated software complexity into two types: accidental complexity, which comes from the limits of tools, and essential complexity, which is inherent to the problem itself. AI addresses accidental complexity - boilerplate, repeated patterns, syntax errors. But essential complexity - the ambiguity in business requirements, the balance between competing design goals, the uncertainty about what will need to change next year - doesn’t disappear no matter how good the AI gets. That complexity comes from the nature of the problem, not the limits of the tools.
So even though AI is different from previous tools, as long as humans remain the accountable parties, the skills required for that judgment don’t change. If anything, automating production makes the judgment in quality control more visible, not less.
A coach I work with compared this situation to Buffett's line:"Only when the tide goes out do you discover who's been swimming naked."
I can't think of a better analogy.
This is why it feels slightly off when I see so many developers focused on getting better at using AI.
A year ago, prompt engineering was the big topic. Now it’s skills, parallel agents, AI teams. Six months from now those keywords will probably be gone too.
AI is going to reach a point where a kid typing casually gets good output. Optimizing for tool usage as a competitive advantage in that environment seems like the wrong bet. Focusing only on how to use the tool better might actually be how you fall behind.
I could be wrong about how this unfolds. Nobody knows exactly how fast AI will develop or in what direction, and I’m not an exception. This post is just one developer thinking through the uncertainty.
There’s no right answer. But the tide is going out faster. I hope you find yours before it does.