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:
- experiences matter. the most.
- the Web matters. it's where free experiences can happen.
- frameworks matter. they enable development of Web experiences at scale.
- present matters. it's where the requirements for the next gen are clarified.
- future matters. it’s where the Web experiences get significantly better.
- me. helping to build a better Web with Cloudflare.
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.
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:
- Developer experiences (DX) of those using the framework, common components, and various tools.
- User experiences (UX) in the form of Web applications built with Angular as experienced by the end users of these apps.
- Community experiences (CX) of those participating in the Angular community.
- Team and collaborator experiences (TX) of those contributing to Angular in one of many ways.
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 Web development 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!
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.
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.
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.
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.
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:
- A formalized and composable component model replaced MVC, MVVM, and similar patterns.
- Ahead of time (build-time) compilation or transpilation optionally combined with type-checking via TypeScript enabled us to write code in ways that scaled better (in terms of scaling the codebase, runtime performance, as well as team size).
- Increasingly sophisticated build optimization tools like Webpack, Rollup, Terser and more recently esbuild/swc became the norm.
- Coarse code splitting, and deferred loading graduated from a nice-to-have optimization to a must-have.
- To keep the complexity down and improve the DX, most solutions of this generation offered a command line interface (CLI) for managing and building projects.
- Server-side rendering (SSR) offered as an opt-in optimization became somewhat popular, but the results have been mixed, inefficient implementations combined with increased development and deployment complexity.
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:
Increasing coupling within the codebase, which results in fate-sharing, raising coordination overhead for bigger teams, as well as risks of application-wide outages.
High conceptual complexity that burdens developers and slows down development.
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.
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).
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).
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:
Applications that have multi-regional or global audiences end up with user experiences that heavily depend on the proximity of the client to the "serverless" data-center region(s) that we chose for their deployment. While multi-region deployments are an option, they quickly become complex, expensive, and can in some cases result in decreased performance.
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).
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:
Infrastructure for building planet-scale apps accessible to mainstream developers — that is without the complexity that currently usually only the well-resourced Big Tech teams from Google, Amazon, Meta, and Twitter can handle.
Portability of compute, code and data — will enable code and data to move freely within the network and between client and the server in response to application needs, network conditions, compliance requirements, and resource availability. All of this will result in better resource utilization, and improved responsiveness of UIs.
Monolithic frontends will be replaced by distributed, carefully decomposed server-first architectures that enable scalability and avoid fate-sharing through release independence. Micro-frontends 2.0?
Streaming, which is already a fundamental part of the transport layer of the Web, will play a big role in improving perceived latency. Previous generations of Web solutions only occasionally utilized it to the full extent. Gen 3 solutions will take streaming to heart and piggy back on QUIC's ability to multiplex connections, reduce latency, and increase bandwidth.
Hyper-context-aware application infrastructure will enable custom-tailored experiences based on the user's profile and preferences, device used, geographical location, network status, and experiments enabled.
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.
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.
- Server-first? ✅
- Planet-scale? ✅
- Portability of code and data? ✅
- Distributed architectures? Work in progress.
- Streaming? ✅
- Hyper-context-aware? Not yet, but doable.
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 the 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:
- A long-term mission that is meaningful to me
- The willingness to make hard and principled choices and avoid optimizing for short-term money gains
- Great culture centered around on empathy, diversity, transparency, and trust
- Great people I could collaborate with and learn from
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!