I recently co-hosted a webinar with Martin Casado of a16z and the founders of three software companies driving the adoption of server-side WebAssembly (Wasm): Matt Butcher of Fermyon, Connor Hicks of Suborbital, and Liam Randall of Cosmonic. The ideas that follow are products of our discussion and belong to them — I’m simply sharing my takeaways. You can (and should) watch the discussion here: http://youtu.be/ThRqEkiCHyA
The internet is awash with content defining WebAssembly (Wasm) and its compelling features. I’d recommend reading a few of these pieces, which offer thoughtful summaries of the technology, emerging applications, and deployment architectures:
- Why WebAssembly Belongs Outside the Browser by Matt Butcher, Connor Hicks, and Taylor Thomas
- WebAssembly Everywhere by Luke Byrne
- Wasm: What’s the Big Deal? by Shomik Ghosh
- How WebAssembly Gets Used: The 18 Most Exciting Startups Building with Wasm by Renee Shah
Rather than describe the technology and its features, I will focus on why Wasm represents a technology that rights a few of the wrongs of software architecture design patterns. Said another way, Wasm resolves a handful of software development anti-patterns.
1. The anti-pattern is a commonly-used process, structure, or pattern of action that, despite initially appearing to be an appropriate and effective response to a problem, has more bad consequences than good ones.
2. Another solution exists to the problem the anti-pattern is attempting to address. This solution is documented, repeatable, and proven to be effective where the anti-pattern is not.
Put simply, anti-patterns emerge when the common practice yields suboptimal results relative to another solution. Some examples that should resonate with software developers include hard coding, overplanning, writing spaghetti code, and using god objects. Wasm resolves four types of anti-patterns:
- We’re an [insert language] shop
- New platforms obviating old code bases
- Knowing the deployment architecture
- Taking data to the application
We’re an [insert language] shop
Does the statement above sound familiar? There is a reason job descriptions mention the languages with which their applications are written. Large software teams rely on shared language fluencies for developers to be able to work together — this is an anti-pattern. Wasm lets people choose whatever language they want to innovate in as long as this language can compile to Wasm.
The support for multiple languages as a compilation target also introduces “best of breed” modularity between languages (a.k.a. “the component model”). It doesn’t matter what source language a particular library was written in as long as it can compile to a Wasm binary whose exported functions can be accessed by another language that can import them. Quoting Matt, developers can mix and match their favorite “high-performance Rust YAML library with a Python script without knowing anything about the particular source language.”
New platforms obviating old code bases
This redundant work is an anti-pattern thanks to WebAssembly and the component model mentioned above. Not only does Wasm support a growing list of popular languages, but the language-specific libraries are also increasingly compatible. We’re getting closer to wholesale compiling to Wasm of entire applications written for other intended byte code formats. As support grows for these per-language libraries, the past will actually be compatible with the future. SQLite is an example of this, as is Postgres, whose 1.3M lines of code and decades of work will soon be compatible with Wasm.
Know your deployment architecture
Serverless is one of those elusive design patterns that offers the promise of abstracting deployment architectures from developers. Historically, developers needed to understand the hardware and environments where their applications run. Quoting Martin:
Virtualization doesn’t paper over architectural differences of where you are in the stack…If you’re a developer and developing in browser vs. CDN tier vs. the server, you’re just developing different things because the communication between nodes is different, the amount of memory is different, [and] the assumptions are different.
Containers also require this environmental context. Despite AWS’s best attempts to commandeer the term “serverless,” the same is true with their offerings. The challenge with considering the runtime environment when writing applications isn’t just the incremental cognitive load for developers but also the fragmentation that results.
Imagine you’re building a streaming service — let’s call it Vrime Pideo. To beat Netflix (😅), you need this service to be available everywhere that users might consume your content. This includes all of the device types, from gaming consoles to TVs to mobile devices to set-top boxes (😅¹⁰⁰). Building an application that is compatible across all of these platforms translates to a high degree of fragmentation and complexity. A simple application update with new features and bug fixes requires serious effort.
Wasm offers a solution to this anti-pattern. As long as the target browser or device supports Wasm, you can write single versions of applications that are ignorant of the target deployment environments while still compatible. With this approach, the world looks like this:
This hypothetical story is actually real and what inspired Amazon to adopt WebAssembly for their Prime Video offering. From their blog post about it:
At Prime Video, we’re delivering content to millions of customers on more than 8,000 device types, such as gaming consoles, TVs, set-top boxes, and USB-powered streaming sticks. When we want to do an update, every one of those devices requires a separate native release, posing a difficult trade-off between updatability and performance. In the past year, we’ve been using WebAssembly (Wasm), a framework that allows code written in high-level languages to run efficiently on any device, to help resolve that trade-off.
The author goes on to say:
The Wasm module broadcasts what it needs meaning the platforms take on the responsibility of what should run where.
Taking data to the application
Let’s recap a few core features of WebAssembly:
- Secure — It’s highly secure because code running in a Wasm runtime is sandboxed from the memory and capability constrained.
- Lightweight — Binaries are small and, therefore, use less bandwidth.
- Near-native performance — It runs close to machine code and is faster as a result
- Fast startup times — Wasm does need to create an OS process for every container
These attributes — security, size, speed — mean you can build lightweight applications that can run in environments that don’t have an operating system or processor. Connor introduces an anti-pattern in the webinar:
Data is big, but programs are small. Why are we moving our data to our programs when we could be moving our programs to our data?
Wasm enables developers to execute applications within databases and other application environments as plugins. Instead of shoveling data over the internet via webhooks with network latency and fickle security models, you can instead execute a small executable directly in the database.
Wasm offers a portable security model. It is deny-by-default, capability driven, and can execute in environments that don’t have a CPU or operating system. The isolation means the plugin can’t do anything malicious without explicitly granting the necessary permissions.
Is Wasm a panacea? No. Should we pay attention? It seems like we should. New technologies are best analyzed along vectors. Even though the utility of Wasm is still taking shape, the current trend could push this technology to mainstream adoption. The resulting utility will solve a few current anti-patterns and ignite new infrastructure design patterns.