The new economics of code: verification is the new bottleneck

As AI makes code generation cheap, verification becomes the bottleneck. Here's why strong typing and spec-oriented development are the next major shift in AI-assisted engineering

Ganesh Hananda


If Claude Code can spit out the implementation in our stead, why do we care about programming languages anymore? Why bother arguing over TypeScript vs. JavaScript, or Rust vs. Python? After all, we can give our instructions in English and let the coding agent produce the implementation.

Well, this assumption falls apart the moment we hit “generate”. The reality of vibe coding is that writing code is no longer the hard part. Verifying is.

In the pre-LLM era, the primary bottleneck in software development was code generation. Translating a business requirement into functional code required syntax mastery, algorithmic thinking, and a lot of typing.

Code generation is cheap. Verification is expensive

Today, LLMs have made code generation practically free. You can prompt an AI to build a complex API endpoint, and it will give you a response in seconds. However, this has triggered a massive shift in the development lifecycle: code verification, not generation, is now the bottleneck.

When an LLM generates code, it doesn’t guarantee correctness. Today state-of-art LLMs have advanced from being 60% correct, to 90% correct, to 99.95% correct.

But it’s never 100%, and probably won’t be for a long time. It can hallucinate APIs, misinterpret edge cases, or introduce subtle security vulnerabilities. Because of this, a human must stay in the loop to verify every single line before it hits production.

To understand why this matters, we have to look at the asymmetry of effort:

  • Generation is cheap: We delegate this to LLMs. It scales very well and the costs are relatively cheap – time and money wise.
  • Verification is expensive: We delegate this to humans. Human attention is scarce, expensive, and easily fatigued.

If an LLM saves you ten minutes of writing code but forces you to spend thirty minutes debugging a subtle runtime error, you haven’t actually saved any time. To make AI-assisted development viable, we need tools that drastically reduce the cognitive load of human verification.

Because human verification is the new bottleneck, we need to build the right toolings such that the job is made easier and can be done as fast as possible. And we believe one of the upcoming major paradigm shift will be spec-oriented development.

Instead of focusing on how to write the implementation details, developers will increasingly focus on defining the exact specifications of what the software must do, letting AI figure out the rest.

Strong typing is strong verification

There are plethora of paradigms and technologies one can use to express specifications: Design by contract and test-driven design, amongst others. Type system also plays a big role as it verifies the contract between different modules in your program, and a strongly-typed language provides more guarantees over a weakly-typed one.

To give a rather trivial example, one can see from the definition below that it is easier to determine the expected behaviour of the second declaration compared to the first one, as it encodes more information about the expected input and output.

def find_user(id):
...
def find_user(id: str) -> Optional[int]:
...

There are also other very interesting programming languages out there which takes strong typing to the next level, such as Idris with its dependent types, or Rust with its affine types.

Moving over from programming languages, we give another example from the database world. We’ll use our own TypeQL as an example where we constraint the data using the cardinality feature.

In this example it is only possible to store an instance of a football team with exactly one goal keeper, between three to five defenders and midfielders, and between one to three players in the forward position:

define
relation football-team sub sports-team,
relates goal-keeper as player @card(1),
relates defender as player @card(3..5),
relates midfielder as player @card(3..5),
relates forward as player @card(1..3);

Given that these type declarations must be adhered, it forces the LLM to iterate on the implementation until it gets it right.

Guardrails for LLMs, safety net for human verifier

LLMs perform significantly better when they are constrained. By providing an LLM with strict type definitions, interfaces, or schemas, you drastically reduce its “search space” for errors. The type system acts as a set of logical guardrails, forcing the AI to generate code that adheres to your exact data structures.

When a human developer steps in to review AI generated code they don’t have to read the body of a function to figure out if it’s a string, an object, or null. You can simply look at the return type.

The type checker catches a lot of bugs that coding agents can act on before the code even reach human review stage. Thus it shifts the human’s job from hunting down tedious edge cases to focusing on higher-level system architecture and business logic.

Conclusion

Admittedly, this transition will take some time. Right now, the spotlight is still in LLM generation because watching an AI write an entire application from a single prompt is flashy, novel, and highly marketable. But the novelty will fade when engineering teams realise they are drowning in unverified code and runtime bugs.

In the future we predict strong typing as well as other technologies in the specification/verification ecosystem to be adopted more. Strong typing, test-driven practices, along with formal verification elements will help “bound” AI-generated code from a messy unverifiable black box into a clearly-specified and verifiable module.

Share this article

TypeDB Newsletter

Stay up to date with the latest TypeDB announcements and events.

Subscribe to newsletter

Further Learning

Feedback