AI-First Software Design From First Principles: A Practitioner's Guide

Most teams adopted AI without revising a single assumption underneath it — which is why the output got faster and the systems got worse.
Here’s the question most engineering teams have not said out loud yet: if the model can write the code, what exactly are we supposed to be good at now?
The answers I hear are mostly defensive. Prompt engineering. Reviewing AI output. Knowing which tool to reach for. All real skills, all downstream of the actual shift, and none of them explain the thing I keep seeing in practice — teams that adopted the same tools, in the same quarter, with the same models, ending up in completely different places. One group ships faster and the software holds. The other ships faster and spends the following quarter finding out what it broke.
Same tools. Opposite outcomes. That difference is not about the model.
The Amplifier Nobody Accounted For
DORA’s 2025 State of AI-assisted Software Development put numbers on this. 90% of technology professionals now use AI at work, and more than 80% believe it has increased their productivity. Both of those are unsurprising. The finding that matters is the third one: higher AI adoption is associated with an increase in software delivery throughput and an increase in software delivery instability, at the same time.
Read that again, because it is the whole argument. The tool made teams faster at shipping and worse at keeping things working. Not one or the other. Both.
DORA’s framing is that AI is an amplifier — it magnifies whatever practice it lands on. Strong systems get stronger. Weak systems get faster at being weak.
Which means the interesting question was never “how do we adopt AI.” It was “what does AI amplify in us.” And answering that requires going back further than any tool decision.
Reason From the Problem, Not From the Tool
First-principles thinking is one of those phrases that has been repeated into meaninglessness, so let me be specific about what I mean by it and what I don’t.
Reasoning by analogy is what most AI adoption looked like. We had a development workflow. A new capability arrived. We asked where the capability fits into the workflow, added it at the point of least resistance — usually code authoring — and kept everything else the same. Standups, tickets, sprints, review, all preserved. The workflow was treated as a given and the tool was fitted to it.
Reasoning from first principles asks a harder question. Strip the process back to what is actually, physically true about building software. Then ask which of those truths the model changed, and which it did not touch. Rebuild from what survives.
Do that honestly and you find that AI changed exactly one thing — and it isn’t the one the category has been selling.
The cost of producing code went to nearly zero. The cost of deciding what the code should be did not move.
Everything useful follows from that single asymmetry. Below are the four consequences I would want any practitioner to be able to state from memory.
One: The Data Model Is the Product
The screen is the most volatile part of any application and the most tempting place to start, because it is the part you can see. It is also the part that should be cheapest to throw away.
The data model is the opposite. It decides what you can ask, what you can index, what you can change later without a migration that scares everyone. Every downstream capability is constrained by choices made — or improvised — at that layer.
When code was expensive, this ordering enforced itself. Nobody hand-wrote a hundred screens against a schema they hadn’t thought about, because hand-writing a hundred screens took a quarter. Generation removed that natural gate. You can now produce an entire interface against a data model that no human ever reviewed, and it will look finished.
So the ordering has to become deliberate. Model first, then contract, then interface. Not because it is traditional — because it is the only order in which the expensive decisions get made while they are still cheap to change.
Two: A Deferred Decision Still Gets Made
This is the one practitioners underestimate.
Every decision you don’t make explicitly is still made. It is made by the generator, at generation time, from context that does not include your business, your compliance surface, your migration history or your plans for next quarter. The model does not decline to decide. It picks something plausible and moves on.
What can a user with a cancelled subscription still see? What happens when two people edit the same record? Is an email address unique, and unique across what? Nobody prompted those questions, so nobody answered them — and the application now has an answer to all three, chosen by inference, discoverable only by hitting it in production.
This is the mechanism behind what builder communities named the 70% problem. Progress stalls not because the remaining work is hard, but because the remaining work is blocked by decisions that were made silently, several hundred generations ago, and can no longer be changed without pulling the whole thing apart.
The practice that fixes this now has a name: spec-driven development. Write down the requirements, the constraints and the success criteria first. Treat that document as the source of truth. Let the agent build against it. GitHub shipped Spec Kit, AWS shipped Kiro, and the convergence is not a coincidence.
Three: When Generation Is Free, Constraints Have to Be Written Down
For decades, correctness was partly carried by the cost of writing code. A developer implementing a rule had to hold the rule in mind. Tacit knowledge in a human head was an acceptable place to store a constraint, because a human was always in the loop.
That storage location no longer works. If a constraint is not expressed somewhere machine-readable — a schema constraint, a type, a validation rule, a test, an explicit line in a spec — it does not exist as far as the generator is concerned. It exists only in the memory of whoever is about to be surprised.
This is the practical core of AI-first design, and it is unglamorous. Push invariants down into the layer that can enforce them. Not-null and unique in the database rather than in a form handler. Types at boundaries rather than in a code comment. Authorization as a policy the system evaluates rather than a condition somebody remembered to write into an endpoint.
Every constraint you externalize is a decision the model can no longer get wrong.
Four: You Are Now Building for Two Consumers
The last one is the newest, and the one most teams have not internalized at all.
Your application has two kinds of user now. One is a person looking at a screen. The other is an agent calling an API, which never sees your interface and cannot be persuaded by good design. If a capability exists in your UI but not in your API, then as far as the agent economy is concerned it does not exist.
That has a design consequence: parity is not a nice-to-have. Anything a human can do through the interface should be reachable through a defined, documented, discoverable surface. Which is also why GraphQL has been a better fit than REST for agent consumption — a self-describing schema is something a machine can explore without a human writing integration notes first.
Build for the agent and the human interface gets simpler as a side effect. Build only for the human and you will be retrofitting an API under deadline pressure, which is the worst possible time to design one.
What Skipping This Looks Like in the Data
GitClear analyzed 623 million code changes from 2023 to 2026, and the maintainability picture is consistent with everything above.
Against a 2023 baseline, duplicated code blocks are up 81%. Within-commit copy/paste climbed from 9.4% in 2022 to 15.7% in the first half of 2026. Error-masking constructs are up 47%. Meanwhile cross-file function calls — the clearest available signal of code reuse — are down 35%, and refactoring activity collapsed from 21% of changes in 2022 to 3.8% so far in 2026.
Developers are now roughly five times more likely to copy and paste than to refactor. In 2022 that ratio ran the other way.
None of that is a model quality problem. Duplication instead of reuse, error handling that swallows rather than surfaces, refactoring that stops happening — those are what you get when generation is cheap and structure is nobody’s explicit job. The output is locally plausible and globally incoherent, which is precisely the failure mode a screen-first workflow cannot detect.
How to Work This Way, Starting This Week
None of this requires a reorganization. It requires changing the order of four or five habits.
- Write the data model before the first screen. Entities, relationships, cardinality, what makes a row unique, what cascades on delete. An hour here is the highest-leverage hour in the project, and it is the one the tools actively invite you to skip.
- Make the spec the artifact you review, not the diff. If the specification is right and the generation is faithful to it, reviewing thousands of lines of generated code is theater. Review the document that produced them. Argue about the spec while arguing is still cheap.
- Externalize every constraint you can name. Before generating, list the rules that must never be violated and put each one somewhere the system enforces it. Anything that stays in conversation will eventually be violated by something that never joined the conversation.
- Design the API as the product surface. Then treat the human interface as one consumer of it. This is a sequencing choice more than an engineering one, and sequencing it late is what makes it expensive.
- Instrument for instability, not just throughput. DORA’s finding is that speed and fragility rose together, so measuring only velocity will show you the good half of your own trend. Change failure rate and time to restore are the numbers that tell you whether the amplifier is working for you.
What This Costs
I want to be straight about the tradeoff rather than pretend there isn’t one.
Working this way is slower for the first week of a project and materially faster for every week after. That is a real cost, paid up front, at exactly the moment when momentum feels most valuable and a competitor is shipping something visible. There will be sprints where the team that skipped all of this looks like it is winning.
It is also not free in discipline. Writing constraints down is less enjoyable than watching an interface appear. Reviewing a specification is less satisfying than reviewing code. These habits decay under deadline pressure, which is the same pressure that makes them matter.
And some of it genuinely does not apply. If you are validating an idea this weekend and intend to throw the result away, throw it away — none of the above is worth doing for software with a two-day lifespan. The argument here is about the applications that outlive their demo.
The Part That Was Never Automatable
Some roles built around code production will shrink. Some will disappear. Pretending otherwise helps nobody prepare, and the people telling you every engineering job is safe are not doing you a favor.
But look at what the asymmetry actually did. It automated the expression of decisions and left the decisions themselves entirely alone. What to build. What not to build. Which invariants hold. What the system must never do. Where the boundaries sit and who is allowed across them.
That work was always the hard part. It was just hidden underneath the labor of typing, which was expensive enough to look like the job.
The typing was never the job.
Related Reading
The practice in depth: spec-driven development. If you are choosing a tool: the best AI app builders in 2026.
Frequently Asked Questions
What does “AI-first software design” mean? Designing an application around the assumption that most code will be generated rather than hand-written, and that some consumers will be agents rather than people. Practically it means the data model, the constraints and the API contract are defined explicitly up front, because those are the decisions generation cannot make for you.
How is AI-first design different from just using AI coding tools? Using AI tools adds a capability to an unchanged workflow. AI-first design changes the workflow’s order of operations — model and contract before interface, specification as the reviewed artifact, constraints pushed into enforceable layers. DORA’s 2025 research found AI adoption raised throughput and instability together, which is what happens when the tool changes but the practice doesn’t.
What are the first principles of software design in an AI era? Four hold up: the data model is the product and the screen is a view of it; any decision you don’t make explicitly gets made implicitly by the generator; constraints must live somewhere machine-enforceable rather than in someone’s head; and your application now serves both a human interface and an agent-facing API, which need parity.
Does designing this way slow teams down? It front-loads work rather than adding it. The decisions captured in a data model and a specification are decisions somebody makes regardless — either deliberately at the start or implicitly by a model guessing later. The second path is where rework comes from, and rework is not faster.
Is spec-driven development the same as AI-first design? Spec-driven development is the practice; AI-first design is the wider set of architectural consequences. SDD covers writing the specification and generating against it. AI-first design also covers data modeling order, where constraints are enforced and designing for agent consumers alongside human ones.
When is it fine to skip all of this? Prototypes, demos, internal one-offs and anything you plan to discard. The overhead is only worth carrying for software that has to survive real users, real data and change over time.


