 Okay. I want to start by saying I'm not an expert in WebAssembly, and I've never even written a line of code for the browser. So take everything I say with a grain of salt. I'm also going to assume very little knowledge of WebAssembly, and start with an introduction to WebAssembly, and then move on to motivating, using WebAssembly to kind of bring reactive concepts to the Internet of Things, and solve some problems that I'm currently facing. And this is a food for thought presentation, and I welcome your feedback on these ideas. So before I start, this talk represents my personal experiences, doesn't represent my employers past or present. I'm currently employed at Tesla. My perspective comes from working on building software for operational technology, so software for services that are controlling physical things or providing critical functions. So first, what's WebAssembly? It's a portable binary intermediate language that can be targeted from various programming languages and execute on different platforms through a virtual machine. Many languages can compile to WebAssembly, so C, C++, C sharp, Rust, Python, Swift, Go. It is somewhat unique in how many languages can compile to WebAssembly, but the idea in and of itself is not unfamiliar to us, right? We scala Java closure, all compile to Java bytecode and execute in the Java virtual machine, and all the .NET languages compile to the common intermediate language and run on the common language runtime. So this idea is something we've been working with for a while. WebAssembly was released in 2017, and it's now supported by all of the popular web browsers. It was originally developed to enable high-performance applications in client web pages, so you could write really efficient code in C++ and then execute that in the browser. And there's these kind of prominent examples of, I don't want to say legacy code, but applications that have been around for many years being ported to the browser, including Google Earth, Adobe Photoshop, and Autodesk, AutoCAD. And if I understand correctly, all three of these cases, WebAssembly was porting decades-old C++ to run in the browser a much more flexible and portable environment, and these companies maintained their significant investment in the code that they already had. But WebAssembly has also become much more important for things other than just like porting legacy code. The web is a really dangerous place, right? We download and run untrusted code all the time in our browsers, and WebAssembly has a very unique sandbox security model that's attractive. The size of the binaries are also important. If you're on a constrained network, the faster you can download a binary, the more reactive your application is going to be, and it's also important that that binary execute quickly and not over-consuming resources so that we can build responsive applications. And these are all characteristics of the browser that are really attractive for the internet of things. I want to expand a bit on WebAssembly's sandbox security model. This is a really important feature of WebAssembly. First the host is in full control. The host grants access rather than restricts access, so it's not a permissive model. And the basic instruction set only includes pure functions, math on memory, that's about all you can do. You cannot open ports, you cannot read and write files, you cannot read and write shared memory. There's not even an instruction set to do that. So conceptually WebAssembly is this. You take code in your language of choice, you compile to a WebAssembly binary, and then you load that binary into a sandbox that's running in an application. The application may be in a browser, or it could be outside of a browser. So V8 is the high-performance JavaScript and WebAssembly engine that's used by Chrome and by Node.js. But then there's all sorts of host runtimes, some of which can be run on constrained devices like IoT devices. These runtimes are newer than V8, and there's a lot of innovation happening here, really developing rapidly. Now with such an limited instruction set, basically math on variables, WebAssembly doesn't actually sound very useful. So there's also this thing called the WebAssembly system interface, or WASI, which is a standard set of imports for I.O., inter-process communication, think POSIX. I'm not actually excited about this at all. As we'll see later in the presentation in the context of IoT, I'm more interested in limiting what can be done rather than expanding WebAssembly to build really rich applications that are doing a whole bunch of I.O. I'm not interested in doing that. WebAssembly also promises good performance, so it has just in time compiled or ahead of time compiled, has near native execution, also has predictable performance because there's no garbage collector, and it does support single instruction multiple data for efficient processing of multiple pieces of data in parallel using a single instruction, and this can be attractive in IoT cases for running like forecasting or machine learning models where you're doing a lot of math on vectors. So as I mentioned, I don't program for the browser, so why am I intrigued by WebAssembly? I'm intrigued by using it in the cloud and on the edge for IoT, and let's start with the cloud. So first off, WebAssembly is attractive to service providers who want to run untrusted client code and do so safely and efficiently. A few examples here, Cloudflare and Fastly both accept client code and then move that closer to their customers through their global networks. Red Panda runs client code hosted in event streams. Cloudflare and Red Panda both use the V8 runtime, so the thing that's embedded in Chrome, that's what they chose to use. Fastly originally started developing their own runtime called Lucent, but recently abandoned it for WasmTime, and they're now investing in WasmTime. So the second thing that's attractive in the cloud is WebAssembly can be used to abstract the runtime, and I need to take you on a bit of a detour in order to motivate this problem, but it's a detour that Jonas has already hinted at in his talk this morning. So this is really a problem of concordance. And concordance is this tension between agreement and consistency, as well as allowing diversity at the same time, but still understanding what's where. So we used to build services and manage the whole stack, right, from the hardware all the way up to our application code, and then with the introduction of virtualized hardware and the hypervisor, we could run many operating systems on that host. And this is where we are today with containers and orchestration, declarative management, but let's look inside those containers. I think this is where the problem still exists. So inside that one of those containers, you're probably pinned to some kind of Docker image. You might have installed root CA certificates and some tools. Then you get to your application binary, which maybe has an HTTP server. And you have some kind of library for parsing JSON. Maybe you also expose a gRPC endpoint. You publish some events to Kafka. You have Prometheus metrics so that you have observability. Now, if that application needs to store state, maybe it's paired with another container in a deployment that has a database that persists state. That means you have a client library for that database. And then finally, we get to this thing that we call the app that has our business logic. And maybe you have tens of services like this, and that allows your teams to work independently. And perhaps you've inherited some legacy services, or you've slowly introduced new technologies into your stack. And this is still kind of manageable. But this concordance problem becomes a real problem with hundreds of services like this. And just to take an example, let's say that there's a security vulnerability in that HTTP library that you're using for your HTTP server. Which services are running that vulnerable version? And how do I go patch all of them? Equally, how do we maintain consistency as our programming practices evolve, or we update our libraries over time? So I think, as Jonas mentioned earlier, this trend is just gonna continue. And we're just gonna go higher and higher up the stack in the levels of abstraction. And I would message routing, parsing, persistence, all these kind of things moving down into the infrastructure. And to me personally, I've developed a lot of systems with ACCA. And what this looks like to me is taking the fundamentals that are in ACCA, but instead of that being compiled in your application binary, that's moving down into the infrastructure layer. And I think WebAssembly has a place to play here, especially with its sandbox execution environment. So you're delivering security, and as well as portable code. Clients can develop applications in whatever language they want, and you don't have to be too opinionated about that. And this enables some great things. So if you think today, if you patch your nodes under Kubernetes, no one needs to know about that, right? The nodes restart, the containers move around. Your infrastructure team can actually take care of that without involving developers. Imagine you could do the same thing with patching your HTTP servers or your library for parsing JSON. Something like that. And this was the promise of serverless functions as a service, as we heard earlier. And I definitely think that's the right trajectory. It's just more and more of what is happening there and needs to move into the infrastructure. And in the limit, our applications start to look like just pure functions with our business logic. And there are some examples of platforms looking at WebAssembly for making this kind of abstraction. So Crustlet is for running WebAssembly in Kubernetes. WasmCloud are these portable actors plus a suite of tools for messaging persistence, et cetera. This is the most similar to what I'm familiar with in ACA. And then there's also Suborbital and WasmFlow. And you can think of these, I think, as declaratively composing WebAssembly modules into form of an application. So lots of tiny modules composed into a big application. And I'm sure this week and even yesterday there was a cloud native wasm day, I'm sure there's all sorts of new announcements in this space. It's evolving pretty rapidly. So the third thing that makes WebAssembly attractive in the cloud is portability. And I think the best way to demonstrate this is to move on now and talk about WebAssembly at the edge. So traditionally the cloud runs services for asset management, streaming, persistence, big data, all these kind of things. And from the edge perspective, the cloud's really just been a place to kind of throw your data or fetch your data. But joining data in the cloud can be hard. Operating cloud services can be expensive. And services that are cloud-based only work when that IoT device is connected to the cloud. So really to build great products, the cloud platform needs to extend to the edge and take advantage of the edge computing platform. You might want to run stream processing, data storage, a time series historian, these kind of things locally to complement the cloud. And then also be able to run locally when disconnected from the cloud. This is really important for delivering services for critical infrastructure. And I think WebAssembly could have a big role to play here as well, allowing us to move code from the cloud to the edge or the other way around from the edge to the cloud. I think all of these ideas are best demonstrated through a motivating example. The example is a bit contrived, but hopefully useful for demonstration purposes. So consider a point of sale terminal that displays the price of goods and accepts payment. And I'm going to write the firmware and rust. So we have a function for determining the price that looks like this. And it just takes simply the item count and multiplies it by the unit price. And the price is calculated as follows. The count and unit price here are hard-coded in the example. They'd be external inputs in the real world. The price function that we just saw returns the price. The firmware has protections against nonsensical prices returning an error if the price is impossibly low or high. This is me hinting at safety critical functions that are going to be embedded in firmware and aren't going to change. And finally, we return the price to be displayed to the customer. So to release this firmware to the point of sale terminal, the code must be built, packaged, signed, it must go through component testing and integration testing. Some code might have to go through safety certifications or audit, and it must usually go through some kind of phase distribution where you deploy to certain parts of the world or certain customers first to make sure it's okay and then you continue your deployment around the world. And this process can often take weeks or months to get a code change from the cloud out to your IoT devices on the edge. So let's see what it actually takes to make a code change. So let's say we want to discount prices during off-peak hours. So from 11 p.m. to 11 a.m. we'll charge half price. So returning to that price function will modify it to return the price during peak hours and then we'll return half the price in off-peak hours. And the function to calculate the price then needs to be modified to consider the hour of the day and pass that into the price function. And then we need to go through this process again. We need to build, assign, package, integration test, and then distribute to the IoT devices around the world, all to make that very minor code change. So let's look at what this might look like if we used WebAssembly instead. So the first thing we need to do in order to use WebAssembly is to extract the price function into a library and adding this no-mangle and extern C. This allows the function to be exposed from the library and called from languages other than Rust. This is documented in the Rust documentation. The function can then be compiled into WebAssembly, which is pretty easy in Rust. And next we must load and call this WebAssembly in the firmware that's gonna be running that point-of-sale terminal. And for this example, I'm using the Wasmer client library but you could choose all sorts of those edge client libraries that I described earlier. So the first step is to load the WebAssembly binary and then we create the WebAssembly sandbox and then compile the WebAssembly. This is the jit compile of it. The price function has no imports from the host. So we're not sharing variables from the host into that WebAssembly function. So there's no imports. We create the instance and then import the price function by calling the get-native function. Then the last step is to actually use that function that we've extracted from the WebAssembly. So first we call a method. So this is calling that method we just looked at that loads the WebAssembly, compiles it and returns that price function. And again, this example's a bit contrived. In reality, this only needs to be done once. And then you can reuse that function over and over again. And finally we call that price function with just slightly different calling semantics from what we had before. And the rest of the program stays the same. So comparing side by side, these are the two price functions and the WebAssembly version basically boils down to needing to load that WebAssembly function and then just slightly different calling semantics. But overall, our function pretty much stays the same. Okay, so to conclude the motivating example, let's look at making a code change in this new world using WebAssembly. In addition to off-peak pricing, let's say we wanna introduce happy hour pricing from two to five p.m. So the price function is updated to only return peak prices during these times and otherwise the price is discounted by half. We compile the WebAssembly again. And then it can be used without any code changes to firmware. This is the really important part. The new WebAssembly function must be reloaded but otherwise there's no code changes that need to be made to that Edge IoT device. And this is the key point. This is the climax of the presentation right here. No changes to firmware. So one of the challenges is redistributing that WebAssembly itself. We need to somehow get that to the Edge IoT device. Now that Wasm code is only about 300 bytes base 60 for encoded, so really tiny. And why not take advantage of desired state configuration in order to distribute it? Because that's basically how IoT devices are usually managed. There's some kind of desired state configuration that's synchronized from the cloud to the Edge. So for example we might have desired state configuration that sets the state of the device, the language, the tax rate, something like that. So then just include another string with the base 64 encoded WebAssembly. What I have emitted from this example is signing. So in the real world you'd also sign this WebAssembly so that you can attest it's from a trusted source. And then if we take a look at what used to be a long process of getting a very small code change actually deployed to IoT devices that are out in the field, we can choose now to short circuit that process at any point in time depending on the value of the business and depending on the risk of that change. And packaging also becomes easy. We can just build in and sign a single function that we're gonna distribute. And we can move code from the cloud to the Edge or the Edge to the cloud very flexibly. So this could be something like this billing calculation in the example I have here. You could also imagine an inline stream processing calculation that you build in the cloud and then eventually move to the Edge to take advantage of the free computing at the Edge. This is really gonna I think allow businesses to iterate faster and respond to customer needs faster and a business that can pull this off is gonna have a competitive advantage. Another thing you can do with the WebAssembly code is that it can be shared and it can be shared across platforms. So what you might do first is run that WebAssembly code in the cloud doing some back testing to see, hey, if I make this pricing change, is it gonna be advantageous? And once you decide it is then you move it to the Edge or you might be running a device shadow or a digital twin, something like that, in the cloud running the same code. But if you wanna run that pricing calculation on a mobile device, you can just move the same WebAssembly there. And instead of having to re-implement that pricing calculation, even though it's pretty trivial logic, you don't have to re-implement it in the language for each platform. Every platform can just use exactly the same code. So this point I wanna emphasize that the sandboxing of the host application remains essential and complementary to the sandboxing provided by the WebAssembly runtime. And I'm especially thinking about this in applications for critical infrastructure. So in the cloud, this most likely involves the container or the VM or whatever the runtime is. And at the Edge, it might involve system D, container runtime, app armor, mini jail, these kind of things that are still sandboxing the application itself. That's still important. It's also important, as I mentioned earlier, that the host implements constraints on the outputs that are used for actuation and goes through extensive testing for safety critical functions. I wouldn't propose here iterating on safety critical functions of the firmware using WebAssembly. What I'm proposing is iterating on, say, functions that maybe provide a set point that is then used by safety critical functions in the firmware. So let's conclude by addressing some concerns with this approach. Many people object to changing code at runtime. The first objection is security. But here the WebAssembly offers this very restrictive sandbox. So it's much less dangerous than changing arbitrary code. The code should also be signed. And as I just mentioned, the firmware already needs to protect against bad input and bad output because often the firmware is developed by a large team. So the team that's iterating on what the price function is different from the team that's actually doing actuation and you already need to protect against bad input, bad output. People also object to the combinatorial testing that this involves. So if you can just change code at runtime, then how can I ultimately test all the possible combinations? But IoT devices typically have many configuration parameters and this already has a combinatorial testing problem. So that problem already exists. I don't see that as a new problem. And then also tracking versions is something people mentioned. So a customer calls into your support line. How are we gonna actually, if we can change code at runtime, how do I actually know what code they're running? And to me, this is no different than the problem of what configuration are they running because we can change so many different configuration parameters and tracking those over time. So I see that as kind of an existing problem. Other people question why web assembly? Why this fancy new technology? Why not just use Docker or why don't we just make a custom binary and assign it, download it? Just because a code is signed doesn't mean it's safe. We learned this with the SolarWinds Sunburst attack. So your supply chain is essentially vulnerable. So if the instruction set is large and you can get a vulnerability into a signed binary, well, you can obviously do bad things. So I think that the very, very limited instruction set of web assembly is attractive here because it limits what you can do. If you have heterogeneous devices, well, then you're gonna have to target each architecture. You don't necessarily have portability of your code. You might have large binaries. You might have large containers. You're gonna figure out ways how to download those efficiently to the devices. And if all you wanna do is run a function, you might not wanna pay the startup time of running a container in order to do it. So I think all these problems can be solved, but I think in the limit, in solving them, you're basically reinventing web assembly. So why not embrace web assembly and explore that for solving the problem you're trying to solve? And lastly, how do we pick a client runtime? I think this is actually a concern. It is hard to pick one. There's many, many of them and they're evolving rapidly. I think security here is also a concern. So if you look at V8, it's been around for many years. It's had a lot of scrutiny. Not to say it hasn't had security vulnerabilities, but V8 gets a lot of scrutiny. These client run times have had nowhere near that level of scrutiny and they're gonna need that if we're gonna run these in safety critical applications. But I also think, porting from one of these to another one shouldn't be too bad. You don't have to change the web assembly itself or you don't have to change that price function. That's not changing. It's only the host environment that you're running that's changing and the interfaces are all fairly similar. So I think if you picked one and decided later that you picked the wrong one and wanted to change, that porting to another one actually shouldn't be too bad. And as I mentioned earlier, many, many languages can target web assembly but I think some languages are a bit awkward. So I think if you're porting legacy code to run in web assembly, this has some advantages. But for Python, the interpreter itself is included in the web assembly. For Go, the garbage collection is included in the web assembly. This feels pretty awkward. So I think if you're doing new development, I would prefer to do it in Rust. I think the tooling's better, the performance is great. You can still do functional programming, which I'm partial to. So new development, I wouldn't embrace the idea that you can write code in any language and target web assembly. Okay, to sum up, web assembly, portable language agnostic, small binaries efficient and has this really great strict sandboxing model. Web assembly can provide a competitive advantage by being able to iterate faster and move code from the cloud to the edge or the edge to the cloud. And it also allows us, I think, to abstract more and more of what's embedded in our binaries today down into the infrastructure. If you think this idea is interesting or crazy, please come talk to me. I'm interested in what others think of it. If you, yeah, you want this in written form, if you go to my blog, there's two articles that basically summarize what I've talked about here, and it provides some links to different resources on the subject. And that's it.