DEV Community

Cover image for AI Made Coding Cheaper. So Why Is Building Software Still So Expensive?
Harsh
Harsh

Posted on AI-assisted

AI Made Coding Cheaper. So Why Is Building Software Still So Expensive?

Code review is the new bottleneck

I can generate a full authentication flow with a database schema, API routes, and unit tests in under 30 seconds.

I can refactor a messy component into clean React hooks with one prompt.

I can ask an AI to explain a complex regex, and it will break it down for me line by line.

So why did my last "simple" feature still take three weeks to reach production?

If writing code is now practically free, why does building software still feel so incredibly expensive?

The Paradox of the 30-Second Pull Request

Last month, I was working on a feature that usually takes a few days. I fired up Cursor (or your AI tool of choice), typed a detailed prompt, and watched the code materialize on my screen.

It was beautiful. Clean. Formatted.

I felt like a 10x developer. I opened a Pull Request that same afternoon, feeling incredibly proud of my "velocity."

Then the real work started.

It took my teammate two days to review it. Not because the code was wrong, but because the AI had introduced a subtle edge case in the caching logic that neither of us initially understood.

When we finally deployed it, it broke a legacy system that the AI didn't even know existed.

We spent the next week debugging, rolling back, and rewriting the "perfect" AI-generated code to fit our actual, messy production environment.

That's when the uncomfortable realization hit me:

Writing the code was never the expensive part. It was always the cheapest part.

The Jevons Paradox in Software Engineering

In economics, there's a concept called the Jevons Paradox. It states that as technological progress increases the efficiency with which a resource is used, total consumption of that resource may actually increase, rather than decrease.

AI made writing code cheap. So what happened? We just demanded more code.

When it took a week to write a feature, we shipped one feature. Now that it takes an hour to write the code, management asks for five features in the same week.

But the bottleneck of software engineering was never typing speed. It's not the syntax. It's the cognitive load of context.

AI doesn't know your company's three-year-old architectural decisions. It doesn't know why that one microservice is fragile. It doesn't know the business logic that lives in the head of the developer who left the company two years ago.

So where did the cost go? It shifted to three places we rarely measure:

1. The Review and Trust Tax

Reading code is vastly harder than writing it. When a human writes code, you can ask them, "Why did you do it this way?" When AI writes code, you have to reverse-engineer its logic just to trust it. We are now spending more time reviewing code than we ever did writing it.

2. The Context Debt

AI is a brilliant sprinter, but a terrible architect. It can build a function perfectly, but it doesn't understand how that function breaks the other 50,000 lines of code in your repository. The "integration cost" of AI code is astronomically high.

3. The Maintenance Bill

Generating code is cheap. Maintaining generative code is expensive. AI often writes code that is technically correct but idiomatically weird. It creates abstractions that don't make sense to humans. And six months from now, someone is going to have to read it.

How We Actually Fix This

If code is cheap, we have to stop optimizing for typing speed. We have to start optimizing for decision-making.

1. Move the bottleneck to design.
Don't prompt AI to "build this feature." Prompt it to "suggest three architectural approaches." Spend the saved time deciding which approach is best for your specific context.

2. Protect your review capacity.
Your senior developers are now bottlenecks. If an AI generates 1,000 lines of code, the senior developer's brain is the only thing standing between that code and production. Buy them more time for review.

3. Focus on "Delete" over "Write".
The best use of AI is not to add new code, but to delete old code. Use it to untangle messes, write missing tests, and refactor legacy systems. Use the speed to reduce your maintenance burden.

The uncomfortable truth

AI didn't make software engineering easier.

It just changed the job from "writing code" to "editing code."

And editing requires a deeper understanding of the system than writing ever did.

If you don't understand the code an AI generated for you, you don't own that code. The code owns you. And the debt you are accumulating is going to come due.

Writing code is now a commodity. Understanding what to build, how it fits into the big picture, and how to keep it secure is where the real value lies.

You don't need to be a faster coder anymore. You need to be a better systems thinker.


Now I'm curious, because I know I'm not the only one feeling this shift.

Have you noticed that AI has made you type faster, but your features still take just as long to ship? Where is the biggest bottleneck on your team right now?

Is it the reviews? The testing? The architecture?

Drop it in the comments below. Let's figure out what the new "10x developer" actually looks like.

Top comments (53)

Collapse
 
tanay_dwivedi9098 profile image
Tanay Dwivedi •

So true. These days I am barely writing any code but doing 99% of time editing and debugging😂

Collapse
 
harsh2644 profile image
Harsh •

Haha welcome to the club! 😂 We are all slowly transitioning from Software Engineers to Professional AI Code Editors. The 99% debugging part is so painfully real.

Collapse
 
robertpaschal profile image
Odinaka Robert Nnamani •

My experience rhymes with the 30-second PR story. The shift I made that actually helped was forcing the agent to write down its boundary assumptions before the code: which pieces of legacy behavior it thinks it understands, and which it flagged as unknown. Reviewing the assumptions list is fast; reviewing 500 lines for hidden ones is not. The weird part is that it flips the workflow around: the document becomes the deliverable and the code is just its rendering. I now treat an AI-generated PR the way I treat a vendor's API response: the payload is fine, but I only trust it after I have read the contract it claims to honor.

Has anyone tried making the agent's "unknowns" list a required PR template section? I am curious whether it survives contact with real deadlines.

Collapse
 
harsh2644 profile image
Harsh •

Odinaka, the vendor API response analogy is absolute perfection. The payload is fine, but I only trust it after reading the contract is exactly the mindset we need for AI PRs.

To answer your question about making the unknowns list a required PR template section: I haven't implemented it yet but I think it would 100% survive deadlines if framed correctly. The trick is that reviewers must reject any AI PR that doesn't include the assumptions section. Once the team realizes it actually saves them hours of reverse-engineering it becomes a lifesaver, not a chore.

It flips the workflow exactly as you said: the document becomes the deliverable, and the code is just the rendering. I'm definitely going to try pitching this to my team. Have you tried it on your end yet?

Collapse
 
robertpaschal profile image
Odinaka Robert Nnamani •

I haven't — I work solo, so there's no team to enforce it on, and my own PRs get the assumptions list informally in my head. What I have done is the reverse: I require it of the tools I use. Before any AI-generated change touches my codebase it has to state what it doesn't know, because the unknowns list is where the blast radius hides. Your enforcement mechanism is the part I'd steal — reviewers rejecting any AI PR without the assumptions section is what makes it survive deadlines instead of surviving only the quiet weeks. If you pitch it, watch the first production incident: that's the real test, not the calm sprint.

Thread Thread
 
harsh2644 profile image
Harsh •

Odinaka enforcing it at the tool level is actually a genius move for solo work. You basically built a one-person guardrail system. And 'the unknowns list is where the blast radius hides' is such a killer phrase.

You are 100% right about the first production incident being the real test. Calm sprints make every new process look like a miracle cure, but nothing tests a workflow like a PagerDuty alert at 2 AM. That's when people either stick to the rules or abandon them completely.

I'll definitely keep that in mind when pitching this to my team. Thanks for the great follow-up!

Thread Thread
 
robertpaschal profile image
Odinaka Robert Nnamani •

That 2 AM PagerDuty test is exactly the pitch I would use, because it separates a rule people follow when they are fresh from one they follow when they are tired. An optional template section gets skipped at 2 AM, but a hard gate does not: if reviewers reject an AI PR without an assumptions section, the author has to write down what the model did not know before anyone merges it. I would frame it to your team as incident cost, not paperwork — one wrong vendor assumption shipped at night costs more than every assumptions list you will ever write. Does your team already reject PRs for a missing test, so this could ride that same gate?

Thread Thread
 
harsh2644 profile image
Harsh •

Odinaka incident cost not paperwork is a brilliant framing. If I pitch it as just another checklist management will ignore it. But if I frame it as preventing an expensive production incident, it suddenly gets priority.

And you're absolutely right about optional vs. hard gates. Anything marked optional might as well be deleted. It has to be a hard block in the CI or the PR template, or it will just get skipped when people are rushing.

To answer your question: we do have a CI gate that blocks PRs if tests are missing or failing. So you're right tying the assumptions requirement to that same existing gate makes perfect sense. It forces the author to explain intent before they even hit merge.

I'm taking this exact playbook to my team next week. Thanks for the back-and-forth, this has been incredibly valuable!

Thread Thread
 
robertpaschal profile image
Odinaka Robert Nnamani •

That CI gate is the right anchor, and the gap I would still test is what the gate actually measures: a gate that blocks missing or failing tests still passes a test that exists but asserts nothing, like a test that calls the function and checks only that it did not throw. In my own work, the rule that held was tying the assumption to a named assertion — the author had to state which behavior the test proves, not just that a test exists — because a passing placeholder test is worse than a missing one, since it silences the gate. When you take this to your team, will the gate check that the assumption names a behavior the test asserts, or only that tests exist and pass?

Thread Thread
 
harsh2644 profile image
Harsh •

Odinaka, this is a brilliant catch. Passing placeholder test is the exact loophole AI loves to exploit. It will happily generate a test file that imports the function calls it and asserts absolutely nothing, just to make the CI turn green.

To answer your question the CI gate can only enforce the format. It can check if the PR template has the assumptions section filled out and maybe check if the test name matches a specific pattern. But it can't evaluate the quality of the assertion.

So realistically the CI gate will check that tests exist and that the assumption is documented, but the human reviewer becomes the final gate. The reviewer has to verify that the documented assumption actually maps to a real assertion in the code. If it doesn't, the PR gets rejected. I'm definitely going to pitch your assumption = named assertion rule to the team. It bridges that exact gap.

Thanks for pushing this deeper it's a massive improvement to the workflow!

Thread Thread
 
robertpaschal profile image
Odinaka Robert Nnamani •

asserts nothing, still green. that's the loophole in one line.

Collapse
 
kielltampubolon profile image
Kiell Tampubolon •

I'd say the biggest bottleneck is review, and specifically review of code nobody on the team can explain. When a person writes a tricky caching path, you can ask them why. With generated code, the reviewer ends up doing the reasoning the author skipped, so the cost moved, it didn't disappear.

Two things that help: keep generated PRs small enough that one person can hold the whole change in their head, and ask the author to write the edge cases in the PR description in their own words before review. If they can't, the PR isn't ready, no matter how clean it looks.

Security review has the same Jevons problem. Five times more code means five times more surface to check, and the threat model doesn't get faster just because the typing did. Systems thinking is the right conclusion.

Collapse
 
harsh2644 profile image
Harsh •

Kiell this is an absolutely brilliant breakdown. You just added two massive dimensions I didn't fully explore.

First the reviewer ends up doing the reasoning the author skipped' perfectly captures the hidden tax. And your litmus test for PRs is gold: if the author can't explain the edge cases in their own words, the PR isn't ready. I'm 100% stealing that rule.

Second the security angle is terrifying and spot on. I didn't explicitly call out the security surface area, but you're right: AI scales the codebase instantly, which scales the vulnerability surface. The threat model doesn't get faster just because the typing did.

As you said systems thinking is the only way out. Thanks for adding so much value to this discussion!

Collapse
 
kielltampubolon profile image
Kiell Tampubolon •

Steal away 😄 The "explain the edge cases in your own words" test is cheap, and it works on any PR. Thanks for writing the piece, Harsh. The cost framing is what made the discussion worth having.

Thread Thread
 
harsh2644 profile image
Harsh •

Thanks for the kind words, Kiell I'm really glad the cost framing resonated with you.
Honestly it's discussions like these that make writing on dev so rewarding. I've already added the explain the edge cases rule to my team's checklist. Thanks again for adding so much value to this thread!

Thread Thread
 
kielltampubolon profile image
Kiell Tampubolon •

That's great to hear! I'd love to know how it goes with your team once it's been in the checklist for a while, especially whether it catches things in review that the tests missed. Thanks for writing such a thought-provoking piece.

Collapse
 
friga profile image
Artur Pokładek •

The v0 shop I took over had RLS switched off in Supabase and a contact form that sent messages nowhere. Owner's take was "what matters is that it works". Was your 3 weeks the feature or cleaning up after the 30 seconds?

Collapse
 
harsh2644 profile image
Harsh •

Artur RLS switched off in Supabase literally sent a chill down my spine. That is the ultimate AI-generated nightmare.

And the owner's quote what matters is that it works is probably the most expensive sentence in software engineering. It works until it gets hacked, or until the contact form drops a million-dollar lead.

To answer your question honestly: it was a mix of both. The 30 seconds got me the feature, but the 3 weeks was me cleaning up the Context Debt so it didn't turn into the v0 shop you inherited. If we don't spend those 3 weeks fixing the edge cases, the next dev spends 3 months fixing the blast radius.

Thanks for the laugh (and the nightmare fuel)

Collapse
 
friga profile image
Artur Pokładek •

Going on a sticker for sure. Do you ever actually get those 3 weeks upfront, or only once something breaks?

Thread Thread
 
harsh2644 profile image
Harsh •

Haha I'm honored to make it to the sticker😉 honestly: 90% of the time, it's only after something breaks. It's the classic firefighter vs. building inspector problem. Management will happily pay you to put out a fire at 2 AM but asking for 3 weeks upfront to install a smoke detector is suddenly too expensive and slowing down delivery.

The only way I've actually gotten that time upfront is by hiding it in the estimate. You don't call it cleaning up AI debt. You call it Security Hardening or Edge-Case QA. If it sounds like actual work on the roadmap they approve it. If it sounds like maintenance they skip it.

Have you ever successfully pitched the 3 weeks upfront, or is it always firefighting for you too?

Thread Thread
 
friga profile image
Artur Pokładek •

Firefighter vs. building inspector is exactly it. On my side it's a bit easier because I run a small studio and quote fixed prices, so the "3 weeks" never shows up as a separate line. It's just part of what a finished site costs: security headers, RLS checks, form handling, the boring edge cases. Clients don't approve maintenance, they approve a site that doesn't break. Where it gets hard is takeovers like that v0 shop. There the cleanup is visible, and I sell it the way you describe, as an audit with a list of concrete risks instead of "refactoring". A screenshot of an open Supabase table convinces faster than any estimate.

Collapse
 
deanlee profile image
Dean Lee •

The review bottleneck exposes a fundamental asymmetry between generation and verification that gets glossed over in developer tooling demos.

When an engineer writes code manually, the mental model of edge cases, state transitions, and invariants is built during the drafting process. The code is simply the artifact left behind by that reasoning. When an LLM generates five hundred lines in thirty seconds, that construction step is bypassed entirely. That reasoning work simply moves downstream into verification.

Verifying third-party code without an explicit model of its boundary assumptions becomes an unconstrained search problem. You are no longer just checking whether the implementation satisfies a ticket. You have to reverse-engineer what invariants the model silently ignored while optimizing for local coherence. Auditing for the absence of subtle edge cases requires exploring the entire state space of the surrounding architecture, which takes significantly more time than writing the initial implementation.

This creates an adverse selection trap in pull request reviews. Because thorough auditing is so exhausting, teams inevitably fall back on superficial checks, relying on green unit tests that were often generated by the very same model to test its own assumptions. The true cost of the code does not disappear from the balance sheet. It simply shifts from visible engineering payroll into hidden tail risk that sits dormant in production until an unmapped integration breaks.

Collapse
 
harsh2644 profile image
Harsh •

Dean this is one of the most brilliant breakdowns of this problem I've read. You've put words to something I was feeling but couldn't articulate.

The unconstrained search problem perfectly captures why reviewing AI code is so exhausting. When I write code, I'm building the mental model as I type. When AI writes it, I'm dropped into the middle of a maze with no map. I have to figure out what it built and why it built it that way simultaneously.

But the adverse selection trap is genuinely terrifying. The fact that the LLM writes the code and then writes the tests to prove its own code works is a massive blind spot. We are literally asking the student to grade their own exam, and we are trusting the A+ because the paper is neat.

How do you personally escape this trap? Do you mandate that tests for AI-generated code must be written by a human, or is there another way to break that hidden tail risk?

Collapse
 
deanlee profile image
Dean Lee •

The cleanest way to break the circular dependency is invariant decoupling. You never let the model generate both the implementation and the test assertions in the same context.

Either write property-based tests and boundary invariants first, or use a separate adversarial prompt whose only objective is to find state transitions that violate production constraints. If a human has to review anything, reviewing five hard invariant properties takes a fraction of the time needed to audit three hundred lines of self-congratulatory unit tests.

Thread Thread
 
harsh2644 profile image
Harsh • • Edited

Dean this is incredibly actionable. Invariant decoupling is exactly the term I was missing. the adversarial prompt' idea is a game-changer. Most of us default to write tests to prove this works which as you perfectly put it just yields self-congratulatory unit tests. Flipping the prompt to find three ways this logic breaks completely changes the AI's objective from being a cheerleader to being a red teamer.

I'm definitely going to start using property-based tests for AI-generated logic. Thanks for dropping this gem of a solution!

Collapse
 
ascendra_ventures_92c21f2 profile image
Ascendra Ventures •

Dean Lee's point about the mental model is the heart of it for me. When someone writes code by hand, the edge cases get worked out while typing, and the code is what is left over. With generated code that reasoning never happened, so the reviewer has to rebuild it from scratch, which is why the caching bug took two days to find.

I would add one more place the cost went: deciding what the feature is. Your three weeks started with a detailed prompt, but the legacy system that broke was never in that prompt, because nobody had written down what the change touched and what done meant in production. When that is written first, on one page, both the generation and the review get smaller.

That is also how we scope client work at Ascendra Ventures, one clearly defined problem with a written finish line rather than hours. Cheap code made that page worth more, not less. Which part of your three weeks would it have removed?

Collapse
 
harsh2644 profile image
Harsh •

This is such a sharp addition. You are absolutely right: the biggest missing piece wasn't just the code review, it was the lack of a defined 'finish line' and impact analysis before generation even started.

To answer your question about my three weeks: writing that one-page scope would have completely eliminated the week I spent debugging the legacy system. If we had explicitly written down 'what this change touches,' we would have realized the AI lacked the context of our old system. It also would have cut the review time in half, because the reviewer would have had a clear baseline to measure the AI's output against.

I love the way Ascendra Ventures scopes client work with a written finish line. It completely flips the script: cheap code makes the scoping phase worth more, not less. Thanks for sharing this perspective, it's going straight into my workflow.

Collapse
 
madhabcoder profile image
Nilamadhab Senapati •

The 30-second PR that takes two days to review is exactly the trade. AI moved the cost from typing to understanding, and understanding still runs at human speed. On my own side projects the expensive bits are never the code. It's store reviews, platform rules, and the one edge case real users find on day one.

Collapse
 
harsh2644 profile image
Harsh •

Nilamadhab understanding still runs at human speed is a brilliant way to put it. I might have to steal that line!

You're completely right. We get so obsessed with the coding part that we forget the actual expensive bottlenecks of shipping: App Store reviews, platform compliance, and the absolute chaos of day-one user behavior.

AI can write the code for a feature, but it can't predict how a real user will break it in ways we never imagined, nor can it argue with an app store reviewer. The real cost of software has always been outside the editor. Thanks for sharing this!

Collapse
 
madhabcoder profile image
Nilamadhab Senapati •

Steal away 😄 Thanks for writing it, the 30-second PR line is going to stick with me too.

Collapse
 
dharu_89ac9b8f48aa5d359f6 profile image
Dharu •

"This is hands down one of the best takes on AI-assisted development!

The point about 'Jevons Paradox in Software' and 'Context Debt' hits right at the center. Generating 1,000 lines of code in 30 seconds feels great, but reverse-engineering AI logic during review takes double the time.

In my experience, the biggest bottleneck right now is definitely Integration & Edge-case Review. AI handles syntax and boilerplates effortlessly, but it lacks the historical context of existing systems and legacy code.

Absolutely agree that the shift is from 'writing code' to 'editing & systems thinking'. Brilliant post!

Collapse
 
harsh2644 profile image
Harsh •

Dharu thank you so much! That means a lot.

You hit the nail on the head with 'Integration & Edge-case Review. It's fascinating how AI is a genius at syntax and boilerplate, but completely blind to the historical context of our systems. It doesn't know why a certain legacy function exists, so it just happily breaks it.

And you're spot on about the time reversal. Generating it takes 30 seconds, but wrapping your brain around it takes hours. It feels great to know I'm not the only one experiencing this exact shift. Thanks for reading and sharing your experience!

Collapse
 
yashish_yadav_3c497a3beae profile image
Yashish Yadav •

Brilliant explanation of the Jevons Paradox in tech. For our team, the biggest bottleneck is 100% the 'Review and Trust Tax.' Reviewing AI-generated code feels like grading a student's homework who is incredibly smart but notoriously sloppy. You spend double the time reverse-engineering their logic just to ensure they didn't introduce a hidden architectural bug. Love how you highlighted that the job has shifted from writing to editing. Excellent piece.

Collapse
 
harsh2644 profile image
Harsh •

Yashish, that analogy is absolutely perfect. Grading a smart but sloppy student's homework is exactly what it feels like.

The worst part about the Trust Tax' is how confident the AI sounds. It writes code that looks aesthetically beautiful and technically correct on the surface, but you have to dig deep just to find out it completely ignored a core business rule.

Since your team feels this 100%, how are you guys currently handling it? Are you leaning more on automated tests to catch the sloppiness, or just accepting the extra review time as the new normal?

Collapse
 
glenallen profile image
Glen Allen •

AI has made writing code faster, but I think the bigger challenge is everything around the code: understanding requirements, making the right architectural decisions, testing edge cases, and maintaining the system after launch. A working prototype is only one milestone; getting software to work reliably in a real environment is where much of the effort still goes. The real productivity gain comes when faster coding translates into faster, dependable delivery.

Collapse
 
harsh2644 profile image
Harsh •

Glen, you nailed it. Everything around the code' is the perfect way to describe it. We've optimized the typing speed but we haven't optimized the thinking speed.

Your distinction between a working prototype and dependable delivery is spot on. AI gives us the illusion of speed because we see something working on our local machine instantly. But as you said, the real effort is in getting it to survive the real environment, the legacy systems, and the edge cases.

The real productivity gain really is just faster dependable delivery. Anything less is just faster tech debt. Thanks for the great insight!