January 28, 2026

From the V-Model to Real User Feedback

For a long time, the dominant question in software delivery wasn’t how fast we could move, but how early we could find problems, because early problems were cheaper, safer, and less visible to customers.

Long before CI/CD became table stakes, there was a deep, almost academic focus on defect cost curves. The idea was simple and compelling: the later you find a problem in the lifecycle, the more expensive it is to fix and the more damage it does to the customer experience. Entire methodologies were built around this premise. At Accenture, I remember being trained on the V-model. This wasn’t just a diagram, but an operating philosophy of how systems should be built. Verification and validation paired at every stage to catch issues as far upstream as possible. It was expensive and slow.

As someone who moved from development into testing during that era, I bought into this logic completely. It was rigorous, methodical, and intellectually satisfying, even when the outcomes were not.

In practice, this led to heavy front-loaded QA, long test phases, and carefully gated releases. And while it absolutely reduced certain classes of defects, it also produced a different outcome: software that took forever to ship and still failed in ways no one predicted. Ironically, Dr. Winston W. Royce, often credited with the waterfall method, warned against its rigid implementation, stating, “I believe in this concept, but the implementation described above is risky and invites failure.” We spent a lot of years before agile development took off adding many layers ahead of coding and shipping code to meet the highest levels of the Capability Maturity Model. As a developer turned tester, I was all in, but it didn’t take many years to accept the waste in the process.

As tooling improved and test automation became more accessible, the center of gravity shifted again. With the idea of test-driven development and software developers increasingly identifying as software engineers, speed to market became more important. Quality still mattered, but the idea of trying to “bang on things” without real-world feedback started to lose its appeal. When tools like Jenkins made build pipelines programmable and Selenium made browser behavior scriptable, testing began to look less like a separate function and more like a development skill. From there, Test-Driven Development emerged as an attempt to encode expectations directly into the act of writing code.

That was real progress. But it still had a fundamental limitation: you can only test what you think to test. And as one old customer of mine once said, “we have to make it work in the wild.”

What automation actually automated

All of these advances shared a common trait. They made it cheaper and faster to validate assumptions.

Load tests simulated traffic patterns we believed might matter. Functional tests verified workflows we anticipated users would follow. Performance checks caught regressions against known baselines. Even TDD, at its best, was about expressing intent before implementation.

What none of these systems had access to was reality.

Test environments are deterministic: inputs equal outputs. But the web is nondeterministic. Real users behave differently than test scripts. Real devices surface issues no lab environment reproduces. Real networks, third-party scripts, and browser quirks combine in ways that escape even the most thorough QA plans. And when those issues do show up, they show up late, in analytics dashboards, support tickets, or business reviews, long after the code has moved on.

This wasn’t because teams lacked data. Performance metrics, engagement analytics, conversion data — all of it existed. It just lived after the fact, owned by different teams, interpreted through reports and meetings rather than fed back into the systems that created the experience in the first place.

The result was a long delay between cause and consequence. Not in an abstract sense, but in a very practical one: by the time you knew something hurt users, fixing it was already expensive again, both in engineering effort and in customer trust.

The shift that made constant shipping possible

Over time, the industry responded in a different way. Instead of trying to prevent every issue up front, teams learned to ship more frequently, reduce blast radius, and rely on experimentation. Feature flags, canary releases, and A/B testing changed the economics. It became cheaper to learn from production than to speculate endlessly beforehand.

This was a genuine step change. Shipping stopped being a singular event and became a continuous process.

But even in this model, real user performance data has remained oddly detached. It informs retrospectives and prioritization, not construction. Developers still rely on local tools such as browser dev tools, synthetic tests, and intuition, while the richest signals about actual experience arrive later, filtered through organizational layers.

So we end up in a strange place: we are shipping constantly, but still reasoning about experience episodically.

Why MCP mattered to me immediately

When the Model Context Protocol (MCP) emerged, offering a standard way for LLMs to connect to external data, it didn’t register as just an “AI thing” to me. It registered as middleware.

I’ve spent enough time around systems like Vitria, TIBCO, Webtrends, and enterprise SOA to recognize a familiar pattern: decoupling producers and consumers of information, standardizing context, and letting automation do the routing work humans used to do manually. I also remember when developing a connector in Vitria between Siebel Systems and Portal Software’s Infranet took forever to get right, and once either vendor changed an API, the work effort felt just as large all over again. Moving data between systems of record has always been essential, but doing it efficiently has been notoriously hard.

MCP felt like that pattern applied to modern development and AI workflows, with the cost of orchestration collapsing toward zero. The difference this time is that the consumers aren’t just other systems; they’re reasoning engines embedded directly in how software is written and changed.

What caught my attention wasn’t that models could access more data. It was that previously isolated systems could now participate in automated reasoning loops. Analytics didn’t have to end in dashboards. They could become structured, queryable, and composable inputs inside the environments where work actually happens.

For performance data in particular, this was a quiet but meaningful unlock. It meant that real user experience no longer had to wait its turn in the lifecycle. It could inform decisions while code was still being written, while features were still evolving, while fixes were still cheap.

What we started building — and why it kept moving upstream

At Yottaa, this realization didn’t arrive fully formed. Early customer conversations were pragmatic and reasonable: help us prioritize performance problems by business impact, and make it easier to turn insights into action. Create a JIRA ticket. Feed the backlog. Close the loop faster.

But as we spent more time with developers, people working primarily in IDEs, using copilots, and debugging directly in browser tools, a pattern emerged. Even better tickets were still downstream. They still assumed a handoff between insight and action.

If the goal was truly faster resolution, the intelligence had to move upstream, closer to where code is written and decisions are made. Not as another dashboard, but as part of the workflow itself.

That realization forced a series of tradeoffs. We leaned toward operational truth over presentation. We shipped something real rather than waiting for a perfectly framed story. And we accepted that exposing live systems to automated reasoning would surface as many questions as answers.

That was the point.

Performance as the baseline feedback signal

At the same time, development itself is changing again. Copilots, agent-assisted coding, and “vibe coding” aren’t edge cases anymore. They’re becoming normal. Code can be generated, modified, and deployed at a pace that would have been uncomfortable not that long ago.

In that environment, feedback matters more, not less.

Performance is the most basic signal that tells you whether a change helped or hurt real users. Before personalization, before clever optimization, before autonomous systems, performance tells you if the experience degraded.

That’s why I keep coming back to it as a baseline requirement. If systems are ever going to adjust themselves to detect issues, propose changes, and eventually act, they need grounding signals from the real world. Performance is one of the few that applies universally.

What this post is actually about

This isn’t meant to be an announcement recap. It’s my attempt to trace a line from decades of thinking about cost, quality, automation, and feedback, and to explain why this moment feels like a structural shift rather than a feature release.

Once real user performance data can participate directly in the build process, the question changes. It’s no longer “what do we think might happen if we ship this?” It becomes “what is happening, and what should change because of it?” And crucially, that question can now be asked while the answer is still inexpensive.

That’s the loop I’ve been trying to close for a long time. It didn’t close all at once. It probably never will. But it finally feels like the pieces are in the right place. It helps to have a team that understands this loop is structural, not just functional.

I’ve learned to be skeptical of “new eras,” but this one feels less like a moment and more like a long-delayed correction.

And that’s a shift worth paying attention to.

Verified by MonsterInsights