9 min read

Zero-Cost Dependencies

Zero-Cost Dependencies

This is the final essay of a 12-part series called Distilling the Web to Zero. The web is far from done improving - particularly as it pertains to building rich web applications that are, to users, developers, and businesses alike, more desirable than their native-app counterparts. This series is prefaced by defining the biggest challenges on the road towards that goal and the 12 essays that follow explore potential solutions using concrete examples.

Motivation

Since this is the final essay of this “zero-themed” series, it might be interesting to hear what it was that sent me down this year-long idea maze which unexpectedly became the basis for web4.

In short it was my obsession with xUI – a different approach to cross-platform UI development that can span across iOS, Android and the web. Instead of constructing a tree-based hierarchy of components and toiling to get it to operate “well enough” across all platforms, xUI would instead move its abstraction a level higher at the screen-level where it’d be easier to define your UI as a set of desired behaviors. No more components; those become an implementation detail. That way, an app’s look and feel could be free to vary greatly between platforms – critically important in order to achieve that “native feel” and escape the uncanny valley of other cross-platform approaches. This is only recently possible with the advent of modern design systems. Previously the rules of how a UI should look and behave were too undefined and open-ended to have any hope of being implemented in such a manner. Design systems fixed the paradox of choice when it comes to the art of UI design.

This approach might be especially appreciated on the web where UI is default-unstyled instead of default-beautiful like on native mobile. Developers are forced to begin with plain black text on a blank white canvas with plain, unstyled controls. xUI would slingshot devs ahead with a batteries-included, full implementation of three design systems: Apple’s HIG, Google’s Material and Microsoft’s Fluent. UI could be a single codebase that would differ at runtime depending on which platform your browser was running on whether iOS, Android, macOS, Windows or Linux.

Creating this would result in a giant, all-inclusive SDK like the ones you see when installing Xcode or Android Studio. The sizes of these SDKs are measured in the gigabytes. This is simply impossible to do for the web which measures its micropackages in kilobytes. The on-demand nature of webpages necessitates tiny payloads whereas native apps are known to balloon to hundreds of megabytes.

xcode_sdks.png

Thus the xUI dream was dead on arrival, infeasible and impractical due to the fundamentals of the web. Server-side execution (web1) couldn’t offer a rich enough experience. Client-side execution (web2) came with debilitating size restrictions. And hybrid client/server architectures can only offer modest improvements to richness and payload sizes but come at the cost of ballooning complexity.

Before xUI could exist, the web needed a way to build apps with zero-cost dependencies while also achieving zero sacrifice to the user experience. This became the driving force behind the birth of web4 – a new reactive execution model that happens neither on origin servers nor on the client but exclusively on the edge by bubbling events beyond the browser, over the wire to edge-side event handlers. This would allow xUI to grow to gigabytes in size with zero impact to the browser’s payload since its DOM would be manipulated remotely.

Where’s the web’s stdlib?

I’ve had a funny journey with web development. It began back in ‘99 in the era of Perl, PHP and unpredictable JavaScript. jQuery, Node.js, and even Rails didn’t yet exist. But in ‘08, I left the web to build native apps for iOS and Android. 16 years later, I finally had the opportunity to return to web development after missing not just one but multiple transformational shifts on the web.

While I never stopped watching the web grow up from afar, it’s certainly not the same as immersing yourself in the ecosystem. Now that I’m back, it’s fascinating to experience firsthand just how vastly different the outcomes are between web and native development.

With web development, the thing I miss most is its lack of a standard library.

Are young web devs familiar with the concept of a standard library? I’m actually not sure; I’m new here. Most major languages come bundled with one. It’s not something that you have to manually include, it’s more a part of the runtime itself, built and supported by the language’s creators/stewards. Its purpose is rooted in convenience and productivity – to include most of the tools that most developers might need to accomplish most tasks. While languages are often bundled with an stdlib, platforms usually do the same thing conceptually with an SDK. Platform SDKs are a large collection of libraries and tools to help you build apps successfully on a specific platform helping you get up to speed fast, take advantage of the best and unique parts of the platform, and (most importantly in my personal opinion) offer a sense of cohesion in the outcome of its apps. Needless to say, these standard libraries and platform SDKs can often be huge: thousands of APIs across millions of lines of code.

In short, the purpose is to help developers fall into the pit of success.

Meanwhile on the web, <button>Hello world</button> looks the same as it did in the 90s. Unrefined. Unsophisticated. Unopinionated. Instead of falling into the pit of success, the web seems to have adopted an ethos of "find your own way."

It’s fascinatingly different. Not bad. Just different.

I guess it makes sense how the web came to adopt this approach to tooling.

The web must remain platform-agnostic

Exactly which design system should the web adopt when web browsers are meant to operate across any and all platforms? The web, as a platform, cannot play favorites. Any attempt to default one aesthetic to a webapp would be met with criticisms of favoritism and accusations of exclusionism. Don’t you just hate using Material apps on iOS or vice versa, seeing Apple-isms on Android? The only winning move is not to play. Thus, web developers are left to begin projects with basic, painfully plain UI with the full burden of inventing their own aesthetic on their shoulders.

The web and dynamic languages

There’s another reason JavaScript skirts the responsibilities of a standard library or app SDK. Dynamic languages like JavaScript have a notoriously difficult time trimming away dead code, i.e. tree shaking. Compilers for statically typed languages like those used for iOS and Android can effortlessly trim away millions of lines of unused code and minimize the size of their binaries. If this were not the case, native mobile developers would obsessively scrutinize every line of code Apple or Google tried adding to their SDKs.

Meanwhile, dynamic languages are better served by starting with a minimum set of APIs and adding external micro-packages one by one, as needed, Ă  la carte.

This puts the responsibility of fleshing out the platform on the shoulders of the community which comes with the positive side effect of explosive innovation. Without the need for planning or permission, anybody can fill any gap they please any way they like. Indeed the web has been ahead of native mobile on many fronts, like for example, exploring reactive programming models.

While I can appreciate the value of rapid innovation, this lack of authoritative oversight has led to an ecosystem that is more than a little frustrating to use. It results in toolchains that are unnecessarily long, convoluted, and fragile. Finding the right tool for the job can sometimes feel like a full time job in itself and packages all have pet names since they cannot simply be named by what they do. It is akin to walking into Home Depot to buy a hammer except there’s no hammer section, they’re spread out all over and always labeled something clever like Mjolnir or remmaH.

The time it takes for a developer to become productive on the web is far greater than other platforms. It feels like someone installed stoplights on the highway where every 50 feet you must come to a complete stop, evaluate 10 new packages, learn how they’re different and why before proceeding to the next inevitable stoplight. There’s always 10 ways to solve every problem and navigating the best path for your product is never ending and ever changing.

To be brutally honest, it’s chaotic. Chaotic good, for sure. But still chaotic.

None of the above is meant as a criticism. I'm just the type that gets fascinated when I notice butterfly effects in nature and I obsess about understanding the initiating minor differences that caused such majorly different outcomes.

The web’s inevitable next step

So what? The web ecosystem evolved differently than native apps. Big deal right? I certainly didn’t think much of it initially either. In fact, before this project was called web4 it was called something far less significant: Dumb Shell. (I even bought the domain dumb.sh). I figured I would take a few weeks to quickly bang out a minimal library to solve xUI’s dependency-challenge by moving event handlers, state management, and reactivity to the server and bubbling events over the wire. As I stumbled through this particular idea maze, I came to discover the nature of this animal was far more profound than I thought, more than even xUI, and not just by a little. What I was building wasn’t just a library, it could be a movement. It has the potential to unlock the next generation of the web.

Unblurring the line between webpages and webapps

The narrative of the past has been that webpages and webapps are not a binary concept; instead it’s a spectrum – that each website exists somewhere between the two extremes of document or app. The term PWA (progressive web app), certainly implies this.

The reason for this is twofold. One, some categories like ecommerce and social lend themselves well to a hybrid model. After all, they are essentially enhanced product “catalogs” or an interactive “book” of faces, not too far of a departure from the world of “print,” and therefore not too far a departure from the web’s original “document” metaphor.

Apps are not documents however. For some categories, like utilities and games, forcing apps into the web’s document metaphor is akin to growing a garden in the shade and has prevented many categories from flourishing to the extent you see in native app stores. Web4 takes an aggressive stance against the metaphor of a page in order to more closely match the typical programming model of a native app. Doing this requires long-lived state which is finally possible when hoisted out of the browser and onto a nearby server.

As web4 grows, the sentiment about webapps will cease to be considered a spectrum and consolidate into one of three categories:

  1. web1 == documents
    • executes on origin servers
    • mostly long-form content
    • best for informational content like academics, news, and blogs
  2. web2 == hybrids
    • executes in the browser
    • mostly short-form content mixed amongst links and buttons
    • best for interactive content like ecommerce and social networking
  3. web4 == webapps
    • executes on the edge
    • focused on function not content; immersive UI with complex and partial navigations
    • best for productivity and immersive use cases like utilities and gaming

Note: web3 was the web’s crypto generation. Decentralization was an important evolution for the web but is inherently headless and therefore outside the scope of this series which is very much focused on UI.

JavaScript’s monopoly on the browser is over

Hoisting an app’s runtime out of the browser and onto a nearby server means developers are no longer beholden to a JavaScript runtime in order to provide a rich user experience on the web.

For the first time ever, frontend web developers have the freedom of choice when it comes to languages, runtimes, tooling, and ecosystems.

Some might dismiss this as old news since the web grew up in an environment of language-choice with options like Perl, PHP, Ruby, Python, and JavaScript. This misses something profound. This time the output isn't a document, it's an app! This requires a far more sophisticated runtime, something that dynamic scripting languages were never designed to support. Couple that with the fact that The Edge is a far more hostile environment to operate in where latency is the mind killer.

Suddenly ecosystems that have been relegated to the backend all this time like Java/Kotlin, C#, and Go, will see a sweeping rush to the frontend. And with them will come their incredible tooling. This excites me the most. Suddenly frontend web development flips overnight from a scarcity-mindset where packages are bespoke and intentionally minimal to an abundance-mindset where the tools are part of a large and thoughtfully considered system, standardized, industrial strength, well-supported, designed for stability, predictability, and longevity.

ecosystems.jpg

In no way is this a criticism of web1 and web2 creators and artisans like DHH who prefer to hand-pick a lovingly curated set of tools, perfectly suited to their project. It’s a beautiful way to build and I love that they have that option. I’m just excited that now I finally have the option to build webapps the way I build native apps.