· Tim Kleier · Engineering · 7 min read
The Future of Programming: The Abstraction Layers Between Intent and Execution
Today an LLM leaps straight from a prompt to code, deciding everything in between and writing none of it down. The next era of software engineering fills that gap with real abstraction layers: semantics, ontology, operational model, and execution model. Every handoff checkable, nothing guessed.

“A customer should be able to pay an invoice.”
Hand that sentence to a coding agent today and you’ll get a pull request back in a few minutes: a migration, an endpoint, a service function, a couple of tests. Sometimes it’s exactly right. Sometimes customer turns out to mean the billing contact, while the rest of your system has always meant the parent account — and you find out six weeks later, in a reconciliation report.
Both outcomes come out of the same process. That’s the problem.
Between that sentence and that code, a dozen decisions got made. What a customer is. What “pay” does to an invoice. What happens when the amount is short, or paid twice, or paid against an invoice that was already voided. The model decided every one of them, and none of them were written down anywhere you can point at.
The Current Paradigm
That’s the leap: one jump, from a prompt straight to code.
One jump from a prompt to code. The four layers in between still get decided — they just rarely get written down, so nothing can review them, diff them, or hold a correction. Each one is practiced somewhere in the industry. None of them is the default.
The outcome someone wants, in their own words. No structure, no types, no system boundaries — just a goal.
Explicit A sentence. A ticket. A hallway conversation that someone remembered to write down.
Implicit Acceptance criteria stay in one person’s head, so "done" gets decided after the fact. Instead, write the outcome and what counts as done in one place, up front.
Where it already exists User stories, PRDs, tickets, acceptance criteria — universal, and almost never precise enough to hand off.
The vocabulary. Which words carry a specific meaning here, and exactly what each one refers to in this business.
Explicit A glossary with teeth: Invoice — a demand for payment issued against a completed order. Not a Receipt. Not a Statement.
Implicit customer quietly means the billing contact in one module and the parent account in another. Two correct implementations, one wrong system. Instead, define the term once, where every layer below reads it.
Where it already exists Domain-Driven Design’s ubiquitous language, data catalogs, dbt docs, schema registries, controlled vocabularies.
The entities and the relationships between them — what can exist, what each thing holds, and what it points at.
Explicit An Invoice carries amount_due and status, and points at the Customer it was issued to. A Payment settles it.
Implicit Relationships get rediscovered feature by feature. The schema ends up as an archaeology of past tickets rather than a model of the business. Instead, declare the entities and relationships as a model, and let the schema follow.
Where it already exists OWL, RDF and SPARQL go back decades; knowledge graphs run production search; Palantir built a company on programming against “the ontology.”
Operations — the behavior the system allows. Each one names an actor, a target, its preconditions, and the state it leaves behind.
Explicit Pay Invoice — actor Customer · target Invoice where status: Issued · changes Invoice.status → Paid · rule: the payment must equal the amount due
Implicit Every consumer re-derives the rules for itself. The API permits a payment the UI forbids — and an agent will find that gap before your QA does. Instead, name the operation once — actor, target, preconditions, resulting state.
Where it already exists BPMN, statecharts and XState, workflow engines like Temporal and Camunda, DDD aggregates and commands, policy rules in an authorization service — each modeling one slice, none of them the layer itself.
The surfaces an operation is reachable through, and the contract each surface honors.
Explicit One operation, four projections: a REST endpoint, an MCP tool, a queue consumer, a button. Same preconditions, same effects, same errors.
Implicit The tool description and the endpoint drift apart. An agent calls what it was told exists, not what actually does. Instead, project every surface from the one operation.
Where it already exists OpenAPI, protobuf, GraphQL SDL, AsyncAPI, JSON Schema — and now MCP tool definitions.
The actual instructions: control flow, persistence, validation, error handling.
Explicit A pay_invoice function, a migration, a test for the underpayment case, an error path.
Implicit Not possible — this is the one layer we have always been forced to write down. Which is exactly why it absorbs every decision from the layers above it.
Where it already exists Universal. Nobody ships without it, which is why it quietly absorbs every decision from above.
The chosen substrate — framework conventions, libraries, data store, deployment target.
Explicit A Django app, Postgres for state, a background worker for the receipt email, deployed on a container.
Implicit Rarely implicit — but a stack picked before the operations are known will quietly bend the operations to fit it. Instead, choose the substrate after the operations are settled.
Where it already exists Framework conventions, dependency manifests, infrastructure-as-code — well-documented and loudly argued about.
Bytecode, JIT, syscalls, silicon. The layer nobody opens.
Explicit You almost never look — and that is the point.
Implicit Never implicit. Decades of compiler work made this handoff so dependable it became invisible. That is the bar for every layer above it.
Where it already exists Compilers, interpreters, JITs. Fully standardized, fully mechanical, entirely invisible.
The four layers in the middle don’t disappear. They get decided — silently, once per feature, by whatever happened to be in context at the time. Three things follow from that, and all three cost money.
You can’t review what was assumed. The code shows you what the model did, never what it decided on the way. To recover the assumption about customer you’d have to infer it from which table the key points at and which case the tests quietly skip. That’s archaeology, not review — and it’s why the wrong assumption sails through. A diff built on a bad definition looks exactly like a diff built on a good one.
Corrections don’t stick. You tell the agent a customer is the parent account. It fixes the code. Next feature, next session, it guesses again — because there was nowhere for that correction to live. A correction with nowhere to live is a correction you will make again.
It isn’t repeatable. Run the same intent twice and you get two different implicit models. Run it across fifty features and you get fifty of them, each internally sensible, collectively incoherent. Consistency is precisely what a large system needs and precisely what one-shot inference can’t give you.
None of this is a model-intelligence problem, and here’s the test: a very good human engineer, handed that one sentence and no other context, would also produce something plausible and possibly wrong. Not from lack of intelligence. From lack of input.
The Future
Programming has always advanced the same way — add a layer, then engineer the handoff beneath it until the handoff gets boring. Assembly to machine code. C to assembly. Bytecode, JIT, linkers, query planners. Nobody debugs register allocation anymore, not because it stopped mattering, but because that handoff got engineered so thoroughly it went invisible.
Above Code / Program, almost none of that exists yet. Here’s what fills it.
Every layer named, every handoff named. Short hops an agent can take one at a time, each with an artifact you can read and check. Colors mark how standardized each handoff is today.
The outcome someone wants, in their own words. No structure, no types, no system boundaries — just a goal.
Explicit A sentence. A ticket. A hallway conversation that someone remembered to write down.
Implicit Acceptance criteria stay in one person’s head, so "done" gets decided after the fact. Instead, write the outcome and what counts as done in one place, up front.
Where it already exists User stories, PRDs, tickets, acceptance criteria — universal, and almost never precise enough to hand off.
The vocabulary. Which words carry a specific meaning here, and exactly what each one refers to in this business.
Explicit A glossary with teeth: Invoice — a demand for payment issued against a completed order. Not a Receipt. Not a Statement.
Implicit customer quietly means the billing contact in one module and the parent account in another. Two correct implementations, one wrong system. Instead, define the term once, where every layer below reads it.
Where it already exists Domain-Driven Design’s ubiquitous language, data catalogs, dbt docs, schema registries, controlled vocabularies.
The entities and the relationships between them — what can exist, what each thing holds, and what it points at.
Explicit An Invoice carries amount_due and status, and points at the Customer it was issued to. A Payment settles it.
Implicit Relationships get rediscovered feature by feature. The schema ends up as an archaeology of past tickets rather than a model of the business. Instead, declare the entities and relationships as a model, and let the schema follow.
Where it already exists OWL, RDF and SPARQL go back decades; knowledge graphs run production search; Palantir built a company on programming against “the ontology.”
Operations — the behavior the system allows. Each one names an actor, a target, its preconditions, and the state it leaves behind.
Explicit Pay Invoice — actor Customer · target Invoice where status: Issued · changes Invoice.status → Paid · rule: the payment must equal the amount due
Implicit Every consumer re-derives the rules for itself. The API permits a payment the UI forbids — and an agent will find that gap before your QA does. Instead, name the operation once — actor, target, preconditions, resulting state.
Where it already exists BPMN, statecharts and XState, workflow engines like Temporal and Camunda, DDD aggregates and commands, policy rules in an authorization service — each modeling one slice, none of them the layer itself.
The surfaces an operation is reachable through, and the contract each surface honors.
Explicit One operation, four projections: a REST endpoint, an MCP tool, a queue consumer, a button. Same preconditions, same effects, same errors.
Implicit The tool description and the endpoint drift apart. An agent calls what it was told exists, not what actually does. Instead, project every surface from the one operation.
Where it already exists OpenAPI, protobuf, GraphQL SDL, AsyncAPI, JSON Schema — and now MCP tool definitions.
The actual instructions: control flow, persistence, validation, error handling.
Explicit A pay_invoice function, a migration, a test for the underpayment case, an error path.
Implicit Not possible — this is the one layer we have always been forced to write down. Which is exactly why it absorbs every decision from the layers above it.
Where it already exists Universal. Nobody ships without it, which is why it quietly absorbs every decision from above.
The chosen substrate — framework conventions, libraries, data store, deployment target.
Explicit A Django app, Postgres for state, a background worker for the receipt email, deployed on a container.
Implicit Rarely implicit — but a stack picked before the operations are known will quietly bend the operations to fit it. Instead, choose the substrate after the operations are settled.
Where it already exists Framework conventions, dependency manifests, infrastructure-as-code — well-documented and loudly argued about.
Bytecode, JIT, syscalls, silicon. The layer nobody opens.
Explicit You almost never look — and that is the point.
Implicit Never implicit. Decades of compiler work made this handoff so dependable it became invisible. That is the bar for every layer above it.
Where it already exists Compilers, interpreters, JITs. Fully standardized, fully mechanical, entirely invisible.
The bottom three layers you already have. The four in the middle are the ones that get inferred today instead of stated:
Semantics is the vocabulary — not a glossary in a wiki nobody reads, but the binding definition of which terms carry a specific meaning here and what each one refers to. An integration bug is usually two systems that never agreed on a concept.
Ontology is what exists and how it connects. Some of this leaks into your database schema, but a schema answers “how do we store this,” not “what is this.”
The Operational Model answers: what can happen, and by whom? Pay Invoice is performed by a Customer, against an Invoice in status Issued, and moves it to Paid when the amount matches what’s due. Without somewhere to say that once, operations dissolve into the code: a precondition here, a status transition there, a permission check three files away, a rule that survives only because someone remembered it in review.
The Execution Model is how an operation becomes reachable. The same Pay Invoice surfaces as a REST endpoint, an MCP tool, a workflow step, and a button. Written four times by four people, they drift apart immediately. Projected from one operation, they can’t: same preconditions, same effects, same errors, by construction.
None of this is hypothetical. Semantics is Domain-Driven Design’s ubiquitous language and the premise of every data catalog. Ontology has OWL, knowledge graphs running production search, and Palantir’s entire business behind it. The operational model shows up as BPMN, as statecharts, as Temporal and Camunda, as DDD aggregates and commands. Execution has OpenAPI and now MCP. The problem was never that the industry failed to figure these out — it’s that each lives in its own pocket, optional and disconnected, and nothing carries a definition from one layer into the next. That’s the difference between a practice and an abstraction layer.
The middle is also having a moment: Why Agentic Systems Need Ontologies was the most-watched talk at this year’s AI Engineer World’s Fair. The people closest to agents in production are arriving at the same gap from a different direction.
Layering also changes where agents fit. Today we point them at the widest gap on the ladder, which is also the one where their output is hardest to verify. The layered version is many short hops, each ending in something readable: an agent proposes the vocabulary and you confirm it, proposes an ontology and you read the diff, derives operations and you correct the two it got wrong. After that, generation is mostly mechanical — and the closer the input gets to a precise model, the less of the remaining work needs a language model at all.
It runs the other direction as well. An agent that operates your business — not one that writes code, but one that actually pays invoices and escalates tickets — needs the operational model to know what it’s permitted to do and what its actions mean. Prose in a system prompt is a bad substitute for a definition. The same layer that makes generation reliable makes delegation safe.
What we’re building
DNA is a format for writing these layers down. Its three layers — operational, product, and technical — span the middle of the stack, from what your business does through the surfaces that expose it to the substrate it runs on. The operational layer is the center of gravity: people, structures, and activities, with operations that name an actor, a target, the rules that govern them, and the state they produce. Everything below is generated from it. Everything above is a conversation that lands in it. You can poke at the model directly in the Operations demo — define resources and actions, and watch the API surface fall out of them.
One separation worth making: the stack needing these layers doesn’t depend on DNA being the thing that supplies them. If someone else’s format wins, every argument above still holds. The interesting fight is over whether the layers belong on the ladder at all.
None of this makes the leap go away, and for a throwaway script the leap is exactly the right tool. But for the systems a business actually runs on, “impressive most of the time” isn’t the bar. The future of programming isn’t a model that leaps further — it’s a stack that makes the leap unnecessary, one layer at a time, until the top half is as dull and dependable as the bottom.
We’re building DNA Codes to make the middle of this ladder real. If this is how you’re thinking about the problem too, join the waitlist — we’d like to have you involved.