experiences. Web. frameworks. future. me.

After 12 years of working on web infrastructure and Angular at Google, I’ve moved on to help build a better Web and Internet with Cloudflare, with my ultimate goal being to make the world a slightly better place. This transition allowed me to reflect on what I’ve been part of for all these years, and why I've dedicated most of my adult life to this work.

My tenure in the Web infra space has allowed me to observe and influence technological trends that evolve the Web. I believe that if we identify these trends correctly, we'll find that they also inform where the future is heading. A future of the Web, I hope to help build.

This whole post turned out to be much longer than I originally imagined, so I've split it into several sections:

Rocher de Saint-Barth Barthélemy

experiences matter. the most. #

For one weekend in 2009, I believed that I was going to die soon. My doctor told me that Friday that I had cancer. We didn't yet know how bad it was. It seemed serious.

That weekend I thought a lot about life. I was weirdly ok with dying. I don't know why. I had very few regrets, and all of them were around things I didn't yet get to experience.

Our daughter V was just 5 months old at that time, and was simply the most exciting experience that happened in our lives.

I recall lying in bed that Sunday morning and composing in my head a list of things that I wanted V to learn to have a good life. Since I wouldn't be around to teach her, I wanted my partner to have the list so that she could teach her when the time was right.

On Monday morning I woke up and somehow decided that the game was not over for me, and I'd stick around to help my partner teach V these things.

9 months later, on July 5, 2010, I was done with all the surgeries and chemo, and accompanied by crampons, an ice axe, my good friend Rama, and a lot of enthusiasm for living and experiencing life, I stood on the top of Mt. Whitney — a mountain I dreamed about climbing for years and an experience I almost never had.

Igor on Mt. Whitney in 2011

Ever since then I started prioritizing experiences in my life over other things. Not only having experiences, but also learning how to enjoy them, and how to craft and share them with people around me, whether they were friends or complete strangers.

In August of 2010 I joined Google to help make something out of this experimental project called Angular or rather AngularJS back then. 12 years later I left Google, still working on Angular. You can read all about that journey in my good-bye letter from three months ago.

Why did I dedicate more than half of my professional career to a single project? Besides all the amazing people I got to know through Angular, there was one additional and simple reason: I found the art of crafting experiences fascinating and rewarding, and through Angular I got to be involved in crafting experiences of many kinds:

Over the years I got to wear many different hats, try lots of things, see some of our attempts fail spectacularly, while many others turn into something delightful and appreciated by many people all around the world. That experience was challenging and fulfilling.

Through my near-death experience, I came to realize that experiences are all that really matters in our lives. I feel privileged to be alive and I plan on using my extra time to enjoy as many experiences as I can, while learning more about the craft of creating and sharing them with others.

the Web matters. it's where free experiences can happen. #

The invention of the Internet, and the application layer built on top of it — the Web, have dramatically changed who can create and share experiences with large groups of people. Through digital abundance they gave a voice to the unheard, enabling people to connect and share experiences at scale not possible before.

Over the years the Web has become a platform for information sharing, artistic medium, economic powerhouse, and technological marvel all in one. Its unique properties like decentralization and lack of censorship support the freedom of speech, improve equity, and general accessibility of information and opportunities, all of which have improved lives of people all around the world regardless of their background, abilities, disabilities, or economic status.

The Web and Internet being open, free, and inclusive comes at a price, and that price is that the quality of experiences is highly inconsistent. There is no one curating the content, and there is no single right way to build a Web experience. In fact, the definition of what makes a great experience is constantly evolving thanks to innovation and research in the field of user experience design and competitive pressures from native platforms.

I've long held the belief that you can't improve what you can't measure. So in order to improve experiences on the Web we need a way to measure them. Core Web Vitals (CWV), introduced only two years ago, finally give us a way to quantify various aspects of quality of user experience on the Web. These metrics give developers a reliable way to know how well we are doing with our individual projects, but also with improving experiences on the Web overall.

Great experiences require alignment of countless technical and non-technical components, ranging from architecture definitions, libraries and languages used, performance optimizations applied, all the way to color contrast and clarity of alternative text for images. Aligning them all in an ever-evolving ecosystem of many independent parties, all of which continuously innovate, while trying to preserve past investments into libraries, tools, and systems requires distributed consensus. And that’s hard. Compromises, local workarounds, and fragmentation that impacts Web experiences are the result.

frameworks matter. they enable development of Web experiences at scale. #

To achieve a scalable development model for the Web, we’ve created various Web frameworks. The Web frameworks help developers increase repeatability and scalability of development by offering higher level building blocks optimized for development of certain kinds of applications.

Web frameworks often decrease the fidelity of the Web platform by abstracting away some of the low level APIs, but in exchange they also abstract away the platform churn, paper over platform gaps, and ultimately increase development velocity — all of which make mainstream software development on the Web possible, and cost-effective.

While I’m a believer in the Web, I’m also very dissatisfied with the current quality of experiences on this platform. I want richer, faster, more polished Web experiences — not only for myself, but for everyone — and I want to empower just about anyone to build them. For these reasons I’ve spent the last decade enabling developers to build experiences on the Web at scale, and improving the platform and developer ecosystem around it along the way.

If we revisit the history of Web development, we can identify distinct eras or generations that promoted a specific approach to large scale Web development. Each generation pushed the art of possible to a new level by applying a specific mindset to making pragmatic trade offs in development of Web applications.

Generation 0 #

Prior to the 2010s, most Web development used client-server architectures that leaned heavily on servers, and expected only little from the thin clients. Web servers served static HTML, or generated HTML on the fly in response to browser's HTTP requests.

Web applications created in this way required a full round trip from a browser to the server accompanied by a full page reload for each significant user interaction — each new state of the user interface was transferred from the server to the browser as a new HTML document, which the browser rendered. The UI of the applications were rendered as many pages, that's where the term multi-page application (MPA) comes from. Gen 0 solutions were the OGs of MPAs!

Most of the business and presentation logic, if there was any at all, resided on the server-side — written in a language different from JavaScript, which limited code-reuse between the server-side and the client-side.

CGI scripts, and later solutions based on .NET, Java, Python, PHP, and Ruby (on Rails) Web servers were the main representatives of Web frameworks of this era.

JavaScript and client-side Web APIs had only a fraction of today's capabilities so keeping the business and presentation logic on the server-side was really the only pragmatic option.

A big drawback of this approach was high latency of user experience. All the frequent network round trips between client and server, further exacerbated by the high network latency characteristic for this era, resulted in users having to wait many seconds or even minutes before the user inference updated in response to their input.

As the pressure to improve the user experience mounted, developers started to lightly employ JavaScript running on the client-side to avoid network round trips. Client-side input validation, or visual effects that made UIs feel richer were the most common examples of JavaScript usage.

This is when I joined the ride, working primarily with Java and Ruby on Rails.

Generation 1 #

AJAX, jQuery, and GWT became popular in the late 2000s, signaling that we entered a transitional post-gen-0 period. These technologies became transitional solutions that enabled the single page application (SPA) architecture to take off in the early 2010s.

SPAs enabled developers to cleanly separate the backend from the frontend helping the teams and codebases to scale. With SPAs frontend developers could write their entire frontend application with JavaScript, and do it repeatedly, and at scale using well established patterns and a growing ecosystem of JavaScript libraries. For the first time developers could use JavaScript for both presentation and business logic. This was a big breakthrough because it increased developer velocity and improved user experiences.

In the early 2010s AngularJS started as a client-side only JavaScript-based solution for building rich Web experiences — the defining characteristic of the 1st generation of JavaScript-based Web frameworks, which among many others featured Backbone, Ember, and Knockout.

We, the 1st gen Web framework authors, were quite opinionated about how the code ran in the browser and how the application was structured, but for the most part provided little guidance about how to package, build, and optimize the JavaScript code that powered the Web experience.

Some developers optimized their apps on their own, others shipped raw JavaScript source code and unoptimized images and didn’t think much about it.

Twelve years ago when network latency was high, this was good enough in spite of the network bandwidth being limited. Even without further optimizations, the shift from thin-client to think-client architectures resulted in improvements to user experiences by avoiding high-latency roundtrips. Developer experiences have improved as well by decoupling the backend and frontend codebases which decreased complexity and increased development velocity.

These advances enabled applications to grow bigger and UIs to get richer, which unsurprisingly caused the amount of JavaScript code used ballooning out of control. As the applications grew, the client-side-first Gen 1 approaches without any significant payload optimizations and only basic runtime optimizations ran into scaling issues affecting both the user experiences and the developer experiences.

Generation 2 #

In the mid 2010s the scaling issues of the Gen 1 solutions resulted in the creation of the 2nd generation of JS Web frameworks. We had to rethink our approach to make it scale better, with an ultimate goal of improving both UX and DX — in spite of them often having very conflicting needs.

The Gen 2 solutions have been successful and became the norm over the last few years. Solutions of this era include (in alphabetical order) Angular, Ember, Lit, React, Solid, Svelte, Vue, and many others.

The Gen 2 Web frameworks have several distinct characteristics compared to Gen 1 solutions:

The increasing complexity of Gen 2 solutions, and demand for performance, SEO, and various integrations led to a rise of metaframeworks and the JAMStack architecture — Gatsby, Hugo, Next.js, Nuxt, SvelteKit, and many others are great examples of these solutions. These solutions found ways to package Gen 2 Web frameworks in ways suitable for content publishing, e-commerce, and many other use-cases via static site generation, integrated SSR, or both.

One thing that hasn’t changed between Gen 1 and Gen 2 Web solutions is that at their very core they are client-side-first solutions.

Another thing that hasn’t changed, is that we keep on creating bigger and richer applications that require larger development teams or even whole organizations to build them. Once again we are starting to approach the limits of the current generation of solutions.

present matters. it's where the requirements for the next gen are clarified. #

Gen 2 Web solutions have reigned Web development for the past 5+ years, but while the user and developer experience have improved for some, we are far from achieving a satisfactory state.

As our applications keep on getting more sophisticated and the bar for expected user experiences on the Web is set higher, it is getting harder and harder for client-side-first solutions to offer better DX without compromising UX. I'm convinced that we are reaching the limits of current approaches.

There are at least three challenges that Gen 2 Web frameworks will not be able to overcome with our current way of thinking and I expect will result in new generation of solutions:

Gen 2 struggles with increasing payloads #

Various optimizations like code-splitting and lazy-loading help to reduce and modularize the payload transferred to the client, but the efficacy of these optimizations today is usually mediocre because of various factors that trigger deoptimizations in order to preserve functionality, and guarantee compatibility.

Even if all optimizations do the job perfectly, the pressure on what can be included in the critical path JavaScript payload (the first JavaScript chunk to be loaded that renders the initial UI) remains and usually grows over time as the application matures and further improvements are implemented.

Server-side rendering is a common solution, but as I’ll describe in a bit, is not a silver bullet that makes all the problems go away.

Gen 2 struggles with fate-sharing #

With the increasing size of applications and development teams, the risks and consequences of fate-sharing increase as well.

One mistake by a team member responsible for a relatively insignificant feature, can result in a catastrophic performance regression or even functional failure of the entire application. The more developers, the more mistakes, the more frequent regressions and outages.

Developers, especially those building enterprise applications, are increasingly interested in release independence and sufficient isolation between subsystems of large frontends. Today's solutions in the form of client-side heavy micro-frontends (MFEs) are failing to deliver these properties, without sacrificing UX by further increasing client-side payload sizes of the application.

Gen 2 struggles with complexity #

We've built Web frameworks to improve development velocity and increase product quality by creating reusable building blocks, and higher abstractions. Why is it that developers struggle with the complexity of today's solutions? Survey after survey, developers express frustration with the APIs, tooling, build times, all standing in their way to getting their application built.

Today's Web development is hard. And when faced with a constant stream of obstacles and cognitive leaks, Web developers usually settle for the first functional version of the application they are building and rarely have the time or ability to iterate, and improve. And if they do, regressing on hard won UX victories is far too easy.

This is partly why the Web has been falling behind the native platforms in polish and richness of experiences. But not all is lost! The Web is still coming ahead in other crucial areas — universally accessible distribution model, cross platform compatibility, and accessibility to name a few.

The Web does deserve better. Better user experiences, and better developer experiences that will enable these user experiences. Better than those offered by any of the Gen 2 Web solutions today. Gen 2 is starting to hit the ceiling of what can be optimized with the client-side-first approach. Maybe it's time to step back and rethink it.

the return to the server?!? #

The network connectivity, and the ability to run code on the server-side have dramatically improved over the last decade.

Network bandwidth has increased and the network latency has decreased. Starlink (a constellation of low Earth orbit satellites) is a breakthrough for less densely populated areas offering fast, low-latency, and reliable Internet. On the other hand, 5G mobile networks, aggressively rolled out in densely populated areas around the world, enable a growing number of people to carry around mobile devices with better network connectivity than that currently connecting entire households.

Just the other day, I was able to measure mobile 5G connectivity with 9ms latency, 2.4 Gbps downlink and 54 Mbps uplink. This kind of connectivity is still rare, but significant mobile network improvements are happening (at least in my corner of the world, where OpenSignal and Bufferbloat Test have been reporting increasingly better results over the last few months).

5G UW OpenSignal test results

With networks becoming faster, client-side code execution is becoming the new bottleneck. This is especially true for low-end and mid-range mobile devices.

Imagine a future where your server is only 9ms away from your average client, while your client-side device takes hundreds of milliseconds to parse, evaluate, and execute your ever-increasing Gen 2-based Web application. Rather than trying to squeeze more performance from your client, you'd start thinking about how to offload more of the logic to the server-side. That future is coming. And it's coming faster than most of us expect.

Wait, does this mean that the frontend is returning to the serve-side?!? Yes. But, also no.

Gen 0 frontend technologies based on Java, .NET, PHP, Python, and Ruby (on Rails) are a thing of the past and I don't expect much of a resurgence even with all the excitement around WASM (which is great for very specific use-cases, but is too heavy-weight for simple presentation logic).

Gen 2's attempts to make isomorphic JavaScript applications a reality, caused a partial return to the server-side already, but this time by using JavasScript friendly Node.js-based HTTP servers and co-opting client-side-first frameworks to run on the server-side. The code-reuse benefits of this approach improved development velocity, but client-side-first solutions run inefficiently on the server, which increases maintenance and operational costs.

Who wants to roll their own servers (even if virtualized via containers) for mainstream frontend applications anyway? Web development is already hard as is, adding server uptime and resource utilization monitoring, security hardening, and dealing with rollouts of OS (or container) updates is additional overhead that most engineering teams are not (and should not be) eager to embrace.

Serverless in the form of AWS Lambda, Firebase Cloud Functions, Azure Functions, and many others, have made running these Node.js HTTP servers easier, but surfaced two new problems:

Serverless issues aside, there is yet another problem with SSR of Gen 2 Web frameworks — the Gen 2 SSR often results in an increase of the overall latency to make the UI interactive (able to respond to users input).

If implemented correctly, modern SSR does generally improve perceived performance of initial rendering of a UI (as measured by the first contentful paint metric or FCP of Core Web Vitals). Additional benefits include improved SEO support and ability to generate preview snapshots (commonly used by various social applications).

However the client-side hydration (the process through which server-rendered HTML comes alive and turns into a rich client-side JavaScript-based experience) as implemented by all Gen 2 Web solutions, is very payload-size and CPU intensive, and counterproductively often results in higher overall time for the UI to become interactive (as measured by the first input delay or FID metric of Core Web Vitals). Partial hydration is a common workaround for this problem, and it helps, but only within limits.

This is a major problem and hard one to solve with today’s approaches.

There is a lot to sort out still, but one thing is certain, we are entering the era where frontend development will shift away from the client-side, and lean much more heavily on server-first architectures. I’m hopeful that we can avoid the pitfalls of past server-side frontend development approaches, and keep the resulting experiences rich and interactive.

future matters. it’s where the Web experiences get significantly better. #

Does this mean that the wave of Generation 3 Web solutions is starting to swell? I do believe that we are already in the transitional period leading to Gen 3. This transition is not fueled by Web3 however, instead it's fueled by the need of the current Web technologies needing to evolve to address the pain points I mentioned earlier.

It started with increasingly sophisticated workarounds that utilized the Gen 2 solutions in novel ways focused on the server-side and decomposition of monolithic architectures — the island architecture, AstroBuild, React Server Components.

And even more recently, Remix and Qwik showed up, respectively exploring the server-first and html-first Web framework space. These are the solutions that pave the path for many more Gen 3 solutions to come in the future.

What might surprise many developers is that marko, Phoenix LiveView, a Google-internal framework called Wiz, and other less well known solutions have been pursuing the server-first approach for a long time but due to various reasons have not been able to get much love from mainstream Web developers. There are lots of lessons to be learned from the wisdom accumulated by these projects.

While a lot is still up in the air, and a lot remains to be researched, developed, and proven there are several key attributes, that I expect the Gen 3 solutions to have:

The current Gen 2 solutions will need to evolve. Some of them will adjust to meet the new demands and adjust to the server-first world. Many will be replaced by new solutions that will attempt to win the attention of developers. The transition won't be abrupt. Incrementally, piece by piece, we'll move in a direction that results in better experiences for everyone. Along the way we'll learn a lot and push the boundaries of the art of the possible.

me. helping to build a better Web with Cloudflare. #

Last November I joined Cloudflare, a company with a mission to help build a better Internet.

Cloudflare logo

I discovered Cloudflare while exploring ideas that could solve many of the problems plaguing Gen 2 Web frameworks. I realized that the return to the server-side was inevitable, but it had to be a server capable of running JavaScript, and running it efficiently.

By sheer luck I came across a presentation by Kenton Varda called Fine-grained sandboxing with V8 isolates from InfoQ 2019 where he described how Cloudflare built a capability to run JavaScript code on their global CDN network, often at the Edge of the network very close to end users. This JavaScript runtime is called Cloudflare Workers.

Cloudflare integrated Google's V8 JavaScript engine into the highly efficient globally available CDN stack and made it possible to run arbitrary JavaScript code in it. You can think of it as a headless browser running on CDN servers that can open many tabs, one tab per application capable of handling the incoming requests.

The runtime is automatically globally provisioned (no server maintenance), doesn't have any cold-start latency issues, supports streams and many of the latest Web APIs, and is collocated with storage solutions like KV store and Durable objects.

From the technical perspective, Cloudflare has all of the right ingredients on top of which Gen 3 Web solutions can be built. The existing CDN infra that already handles sizeable portion of the global Internet traffic, and the Workers stack have been battle-tested in high-scale environments for many years.

Using Cloudflare Workers today is not as intuitive and simple as it should be, this is however something that with focus and work can be fixed. And if we add a few more missing foundational pieces to the platform, we'll end up with a Web infrastructure capable of hosting the next generation of Web frameworks — the generation that will help make the Web better. This is why I joined.

Leaving Google and the Angular team has been very hard for me primarily because of the awesome people I got to work with every day and the impact we've had on Google and Web development all around the world. This is why my hard requirements for the company I'd join next included things like:

As I got to meet people at Cloudflare I grew more and more confident that I found the new "home" for me. Now I get to work along with awesome people like Rita, Sunil, Ashcon, Nevi, Glen, Pete, Jacob, Kenton, Dane, Michelle, and Matthew.

We are just getting started, but things are already getting exciting. I do believe that Cloudflare will make a big difference in the future of the Web, and I feel fortunate to be able to be part of that journey. I can't wait to see what we'll do together to help build a better Web.

PS: I'd like to express my gratitude to all the reviewers who provided me with valuable feedback on this post, especially Natalia Venditto, Carmen Popoviciu, Pawel Kozlowski, Bonnie Brennan, Glen Maddern, Ryan Carniato, and many others.


Thank you for reading. Share this post with friends! 🖖🏻

Got feedback? Reply to me on Twitter!