Skip to main content
Alejandro Cantero Jódar

From jQuery to Jev: How Web Engineering Got Here

· Programming

From jQuery to Jev: How Web Engineering Got Here

Every few years someone announces that software engineering is over. It never is. What actually happens is quieter and more interesting: we standardize one more layer of the craft, the layer below becomes invisible, and the work moves up. I have been building for the web long enough to have felt several of those shifts from the inside, and the one happening right now looks, to me, like the most exciting of them.

This is a short history of how web engineering got here, told through three threads that keep crossing: standardization (we kept making code look alike), abstraction (each era hides the one before), and a pendulum that swings between server and client. The last swing is starting as I write this.

Pages, then applications: the road to Web 2.0

The early web was documents. A server rendered HTML, the browser displayed it, and every click was a full round trip. Interactivity meant a form and a reload.

Then, around the mid-2000s, the browser learned to talk to the server in the background. The technique got a name (AJAX), the era got a label (Web 2.0), and jQuery made it bearable by hiding the chaos of browser inconsistencies behind $(). The web stopped being a library of pages and started becoming a platform for applications.

I remember this period clearly because I could feel where it was going. Everyone using jQuery ended up writing their own little libraries on top of it: a modal helper here, a form validator there, a homemade way to keep the DOM in sync with some data. Every team was solving the same problems in slightly different ways. It was obvious that those private libraries would eventually harden into something shared. I was riding that wave, and it was a very good place to be.

MVC and the first shared vocabulary

The first big standardization did not come from the browser. It came from the server.

Ruby on Rails, released in 2004, popularized an idea that sounds trivial now: convention over configuration. Put your models here, your controllers there, name your tables like this, and the framework does the rest. Symfony, Django, Laravel and others followed the same path. MVC stopped being an academic diagram and became the default shape of a web project.

The effect on teams was enormous and underrated. If you knew one Rails app, you could navigate most Rails apps. Conventions are a form of shared memory: they encode decisions nobody has to make, or argue about, again.

Patterns for when conventions are not enough

As web applications grew into businesses, MVC started to creak. Fat controllers, anemic models, business rules smeared across layers. The answer came in the form of architectural patterns that were older than most of the frameworks using them.

Domain-Driven Design gave us a language to talk about the business inside the code. Hexagonal architecture (ports and adapters) gave us a way to keep that business logic independent from the database, the HTTP layer and whatever framework was fashionable that year. CQRS told us that reading and writing are different problems and deserve different models. Microservices took these boundaries and turned them into deployment units, sometimes wisely, often not.

These patterns are another layer of abstraction, but at a different level. Frameworks standardized where the code goes. Patterns standardized how we think about the problem. A developer who understands “command handler”, “repository” and “domain event” can walk into a PHP codebase or a Java one and recognize the shape immediately.

Frameworks everywhere, and the knowledge that came with them

Then the frontend went through the same process the backend had gone through a decade earlier. Those homemade jQuery libraries became Backbone, then AngularJS, then React, Vue and the modern Angular. At the same time, package managers (npm, Composer) and platforms like GitHub and Stack Overflow turned every solved problem into something you could install, fork or copy.

This is the part of the story I think we do not celebrate enough. Frameworks did not just make code faster to write. They made teams faster to form. A company could hire “a React developer” or “a Symfony developer” and expect that person to be productive in weeks instead of months. Knowledge became portable. A question asked once on Stack Overflow answered the same question for a million other developers using the same stack.

Keep this in mind, because it comes back later: the whole industry spent fifteen years making code look the same.

The pendulum swings to the client

Single-page applications were the high point of the client. The browser downloaded a big JavaScript bundle, rendered everything itself, and talked to the backend only for data.

That decision had a side effect that turned out to be historic: it turned every backend into an API. Once the frontend was a separate application (and once mobile apps needed the same data), the server’s job became exposing JSON endpoints. REST became the default, OpenAPI documented it, and a whole economy of SaaS products with public APIs grew on top. The world, quietly, became APIfied.

Hold on to that one too.

And back to the server: SSR and the obsession with speed

SPAs had a cost. Blank screens while the bundle loaded, poor SEO, and terrible performance on the devices that mattered most: phones on mediocre networks. Mobile traffic made performance a business metric, and Google made it a ranking one with Core Web Vitals.

So the pendulum swung back. The same frameworks that had pulled rendering into the browser started pushing it back to the server. Next.js, Nuxt, Angular SSR, Astro (which renders this very blog) and friends brought server-side rendering, static generation, hydration, streaming and edge rendering. The jQuery-era instinct I mentioned earlier had come full circle: libraries became frameworks, and frameworks nudged you toward SSR as the sensible default.

                 SERVER                                 CLIENT
                   │                                      │
 Static pages ●────┤                                      │
                   │─────────── AJAX / jQuery ───────────▶│
                   │                                      │
                   │◀────────── MVC frameworks            │
                   │                                      │
                   │─────────── SPAs (Angular, React) ───▶●
                   │                                      │
                   ●◀────────── SSR, edge, optimization   │
                   │                                      │
  AI via API ──────●                                      │
                   │─────────── AI decisions on-device ──▶?   ← next swing

Types: the determinism layer

In parallel, something else was being standardized: the contracts between pieces of code. TypeScript went from a Microsoft curiosity to the default for serious frontend work, and most modern frameworks now scaffold projects in TypeScript out of the box.

Types are an abstraction that removes a whole class of questions. What does this function return? Can this be null? What shape does this API response have? With types, the answer is not in someone’s head or in a wiki. It is in the code, and the compiler enforces it.

This matters much more today than it did five years ago, because types add determinism to a codebase that is increasingly written by something non-deterministic. GitHub’s Octoverse 2025 reported that TypeScript became the most used language on GitHub in August 2025, overtaking Python and JavaScript, and GitHub itself tied that rise to typed languages making agent-assisted coding more reliable. When a model writes your code, the type checker is the first reviewer that never gets tired.

LLMs and agents: trained on our standardization

Now the threads come together.

Large language models are remarkably good at writing web code. Part of that is scale, of course. But think about what they were trained on: millions of repositories that follow the same conventions, use the same frameworks, apply the same patterns and answer the same questions on Stack Overflow. Fifteen years of standardization produced the most homogeneous, well-documented, massively duplicated corpus a model could ask for. Frameworks trained the machines. We did not plan it that way, but the effort we invested in making code predictable for humans made it predictable for models too.

The same is true for agents. When coding and business agents arrived, they did not have to invent a way to interact with the world. The world was already APIfied. Function calling and the Model Context Protocol are, at their core, thin layers over the REST endpoints and SaaS integrations we spent a decade building for SPAs and mobile apps. The field was already irrigated. Agents just had to plug in.

And, as I argued in a previous post, the engineering discipline around them (contracts, tests, types, verification) is still very much software engineering. It is just one layer higher.

The probabilistic if: real-time AI decisions

For thirty years, the if statement has been deterministic. if (user.plan === 'premium'). A programmer decided the rule, wrote it down, and the machine executed it the same way every time.

LLMs let us ask fuzzier questions, but they answer in prose, they are slow, and they are expensive enough that nobody puts them inside a hot loop. That is starting to change, and the clearest example right now is Jev.

Jev is a model from TypeSafe AI, released in limited early access on September 15, 2026. It is not a chatbot. It does not generate text at all. You give it a state (a string or a JSON object) and a set of typed questions, and it returns typed values with probabilities and a confidence score, answering all the questions in parallel in a single pass (Wikipedia). There are three primitives: Choice (pick one option from a set), Score (place something on an ordered scale) and Noul (a probabilistic yes/no). TypeSafe calls it a “System One Model”, built for decisions inside software rather than words for people (typesafe.ai).

Here is what that looks like, adapted from TypeSafe’s documentation (illustrative, the API is still in early access):

import { choice, noul, TypeSafeClient } from '@typesafe-ai/sdk'

const client = new TypeSafeClient()

const { answers } = await client.systemOne({
  state: { message },
  questions: {
    department: choice('Which team should handle this', {
      billing: 'Payment or subscription issues',
      technical: 'Bugs or integration problems',
      sales: 'Pricing or account questions',
    }),
    isUrgent: noul('The message conveys urgency or time-sensitivity'),
  },
})

if (answers.department.confidence > 0.8) {
  routeTo(answers.department.choice)
} else {
  askAHuman(message)
}

Look at the last lines. That is a probabilistic if: a conditional whose condition is a judgment, answered with a type and a confidence level. The mature version of the pattern is confidence gating: act automatically when confidence is high, ask for confirmation when it is medium, hand it to a human when it is low. The type system and the model finally meet in the middle.

A word of caution: TypeSafe claims 70–500 ms latency, a price of $0.042 per million input tokens with free output, and speed and cost advantages of two orders of magnitude over frontier LLMs. Those numbers are self-reported and have not been independently validated yet (flaviocopes.com). Even the exact multiplier varies between TypeSafe’s own site and other sources. Treat the benchmarks with skepticism.

But do not let the benchmarks distract you from the direction. Fast, cheap, typed, non-deterministic conditionals embedded in normal application code are clearly where things are going. Jev is simply the loudest example this month.

The next swing: decisions in the client

Today Jev runs behind an API. Its SDK even blocks browser usage by default, so you do not ship your API key to every visitor. So we are, once again, on the server side of the pendulum.

I do not think we will stay there long. The pieces for running these decisions directly in the browser are already shipping:

  1. Chrome’s built-in AI. The Prompt API exposes Gemini Nano running locally, and it already accepts a JSON Schema through responseConstraint. That is typed output from an on-device model, today.
  2. Transformers.js. Version 4, released in February 2026, ships a rewritten WebGPU runtime and runs models from the browser to Node, Bun and Deno with the same code.
  3. WebGPU and WebNN. WebGPU gives JavaScript access to the GPU, and the Web Neural Network API is now a W3C Candidate Recommendation, with working implementations in Chromium browsers and a path to the NPUs in modern laptops and phones.

Put a small decision model like Jev on top of that stack and you get probabilistic ifs with zero network latency, no per-call cost and no user data leaving the device. My bet: we will see the first serious client-side “System One” style models within the next one or two months. It is an aggressive guess, but every ingredient is already on the table.

Why I am optimistic

It is tempting to read this story as a countdown: every layer we standardize is a layer we do not need people for anymore. I read it the other way around.

Each abstraction in this history (MVC, patterns, frameworks, APIs, types, LLMs) made software cheaper to build, and every time that happened, the world asked for more software, not less. We are nowhere near the point where software is “solved” or has become a basic, foundational skill that everyone just has. Most of the world still runs on spreadsheets, fragile integrations and processes held together by email. The demand for software that is robust and genuinely useful is enormous, and it is not going away.

What changes is where the interesting work lives. Deciding which questions to ask the model, designing the types that constrain its answers, choosing the confidence thresholds, knowing when the decision belongs on the server and when it belongs in the client: that is engineering. I felt the wave coming in the jQuery days. I feel the same wave now.

Quick Takeaways

  • Web engineering history is a story of standardization: conventions, patterns, frameworks, APIs and types each made code more alike and teams faster to form.
  • The server/client pendulum keeps swinging: pages, AJAX, SPAs, SSR, AI via API, and next, AI in the browser.
  • LLMs are good at web code largely because we spent fifteen years making that code homogeneous, and agents plugged into a world that was already APIfied.
  • Types matter more than ever: they add determinism to code written by non-deterministic models.
  • Models like Jev introduce the probabilistic if: fast, typed, confidence-scored decisions inside application code. With Chrome’s built-in AI, Transformers.js and WebNN, those decisions are about to move into the client.

Conclusion

We did not get here by accident. Every generation of web developers standardized something, and that shared foundation is exactly what today’s models are built on and plugged into. The next abstraction is not a framework or a pattern. It is the decision itself, typed and probabilistic, running wherever it makes sense, increasingly on the user’s own device. Software engineering is not ending. It is getting a new primitive.

  • I’m Not Working With Humans Anymore (Sadly)

    · Programming

    Code reviews used to feel like conversations with real people. Now they often read like the same polished template, and it’s changing how I think about engineering, collaboration, and where human value actually lives.

  • Claude Code and the New Coding Monopoly of 2026

    · Programming

    In 2026, a growing majority of the world’s software is written by AI, often inside centralized cloud platforms like Claude Code. This article explores why that concentration of code generation power may become a critical dependency and a serious security risk for the software industry.

Continue reading

Why I Built My Family a Private AI Assistant Instead of Handing Them ChatGPT