Building for a future based on WebAssembly

Building for a future based on WebAssembly

My goal with the Suborbital project is contributing to the WebAssembly community in the form of tools, frameworks, and a platform that makes building web services with WebAssembly useful in the real world. I believe that WebAssembly is a technology that will enable simpler, safer, and more flexible server applications. In order to acheive this, I want to outline a clear plan for the project, and I also need the help of the community to help shape the vision of what's being built.

I have a lot to say about WebAssembly, and I've spent the last year working on building server-side capabilities for it, so I wanted to share some of those thoughts here in one place. We have seen some great adoption of WebAssembly, including support in the major browsers, the evolution of WASI, more language toolchain support, and real-world use-cases such as Shopify and The Internet Archive.

I've laid out some of the design patterns that Atmo is being built around, and now I want to talk about some of the core aspects that make it compelling as a development platform. The first is declarative application development.

Declarative development

Just as Kubernetes popularized declarative infrastructure, Atmo strives to introduce declarative application logic. When developing an Atmo application, you write isolated, independent functions called Runnables that are compiled to WebAssembly. Since these functions are completely unaware of one another, there needs to be a way to string them together in order to create business logic. Atmo does this using a file called the Directive. Here's an example:

identifier: com.suborbital.test
version: v0.0.1

handlers:
  - type: request
    resource: /user
    method: GET
    steps:
      - group:
        - fn: modify-url
          as: baseURL
        - fn: get-user
          as: user
      - fn: fetch-details
        with:
          - "url: baseURL"
          - "user: user"

This includes a full description of how to handle a request to the GET /user endpoint. It describes not only what endpoints are available, but how they should be handled. The functions called are completely independent, and are able to carry out the request by interacting with Atmo's APIs.

As seen above, function groups allow multiple Runnables to execute concurrently to aid in fetching data from a large number of sources or performing many different data manipulation tasks simultaneously. Atmo's scheduler automatically handles this execution and coordinates running all of the functions needed for a request. The as and with clauses make it easy to manage state and function input/output.

The end of boilerplate

One of the key goals of Atmo's design is that no boilerplate code is needed. The only things you need to do are write your functions and define your Directive. There's no need to configure a webserver, bind to ports, build a router, etc. Everything is packaged into a Runnable Bundle and Atmo uses it to automatically build your server.

This is important for a number of reasons. Firstly, it is a boon for developer productivity, as creating new projects is vastly simplified. A simple subo create project command creates everything you need to get started. Secondly, it makes onboarding new developers easier as they don't need to reason about how you've set up your particular project. There's one consistent entrypoint and an easy to understand project structure.

Polyglot, for good reason

WebAssembly is a common format that can be leveraged to make application design easier, but it can also simplify vendor APIs as well. A long-term goal for Atmo is to allow Runnables from your own team as well as third parties to coexist in harmony. It shouldn't matter if a vendor wrote a library in Rust, C++, Go or Swift. Atmo will make it easy to chain together third party modules with your own to easily interact with third-party APIs. Vendors would only need to build their API once, rather than distributing libraries in multiple languages. Mocking out for testing would be made easier, as third party modules could be easily swapped for test versions in CI/CD to make testing your system simpler.

Flexible operations

Since the entire Runnable Bundle for an Atmo application is loaded at runtime, plenty of capabilities become available such as hot-reloading business logic, instantaneous rollouts and rollbacks, multiple simultaneous application versions, and more. Making changes will no longer require restarting a process and dropping or draining network connections, as your application can be upgraded in real-time while requests from an older version are still being handled. WebAssembly brings many capabilities like these that were previously difficult or impossible, and it really highlights what is possible.

Meshing to the core

As laid out in the SUFA design pattern, the ability to scale out a flat network of instances is one of the capabilities enabled by Atmo. This is more than just linking instances, it is truly meshing together your application's business logic down to the core scheduler.

Atmo uses Hive and Grav to mesh not only the instances together, but the execution of each request. Capability groups are designed to increase the security of your system, and meshing allows individual functions to be executed on privileged instances, and then immediately transfer execution back to non-sensitive instances, meaning that the exposure to resources is more tightly protected.

Request state

As shown above with the as and where clause, Atmo uses a novel approach to pass data between functions in a request chain. Each step in a handler produces output, and when the step completes, that output is saved to an ephemeral state object. This state is available to every Runnable in later stages, allowing access to the data produced by previous steps. as allows storing a function's output into state under a particular name, and with lets the developer define a 'desired state' to pass into a function, effectively choosing what should be provided as input.

Request state is automatically managed by Atmo, and is created for each request as it's handled. State has been designed to be serialized, such that it can be shuttled over the wire by Grav when request meshing is being used. This means that functions executed on a meshed instance gets access to the same state, no matter where it's running. This flexible data handling technique makes developing asynchronous and distributed compute simple and completely managed by Atmo.

What's next

I've just described a number of unique features that makes Atmo a new and exciting way to develop your web services, but the Suborbital project is still in its early days. Atmo is still in Alpha, and while it is showing great promise, it is not yet ready for production workloads. There is an immense amount of work that needs to be done in order to realize the goal of having a viable and well-adopted server-side WebAssembly platform, and for that I need the help of others. There are many ways you can help, and I welcome all of them, but there are two things in particular that I am asking for today.

Take the survey. I've created a 3-minute survey to learn more about the community's thoughts about WebAssembly on the server so that I can inform decisions that need to be made about developing Suborbital. I would greatly appreciate responses, as it will help ensure that I am building something that developers would be excited to build with.

Take the survey

Give it a try. While not ready for production workloads, trying Atmo and giving me your feedback is the most helpful thing that you can do right now. All of the tooling, infrastructure, architecture, and design patterns are brand new and hearing how you use it (or even better, fail to use it!) helps me to determine what can be improved, added, and fixed to make the project production-ready.

I am also open to any and all contributions from the community. I am more than happy to meet with anyone interested in working alongside me to build these capabilities so that I can help get you started developing Atmo, Vektor, Grav, Hive, and Subo. Developers with no experience working with WebAssembly, distributed systems, web services, or Go are encouraged to join and I will do whatever I can to help you learn what's needed to contribute. Open Source is not just about developing in the open, it's also about helping others learn.

This was a very long post, but I hope it helps communicate what I am working towards with the Suborbital project, and most of all I hope it gets you excited about the future of WebAssembly and how it can shape the next generation of applications in the cloud.

If you want to be kept up to date about Suborbital and WebAssembly on the server, please sign up using the form below or by providing your email address in the survey (which is optional, of course). If you want to get in touch, please feel free to reach out via Twitter or via our GitHub discussions

Cover photo by Nastya Dulhiier from Unsplash