Terrier SDK’s Cross-Platform Power: Web Assembly in Action

Written by Steve Gifford

August 7, 2024

In the Terrier SDK’s web version, we heavily use Web Assembly. It powers the real-time data rendering we rely on and lets us share that code between web and mobile.

What is Web Assembly?

Web Assembly, WASM, for short, is very exciting in a very boring way. It’s binary code you can run in a web browser. Web Assembly allows us to bring high-performance computing to the browser environment.

If you’re my age, you’re probably thinking, “Didn’t we do this with Java 20 years ago?” and you’d have a point. We did, but it was kind of bad in a way I can’t quite remember. A certain fuzziness of memory is good for your sanity in technology.

Anyway, Web Assembly is pretty sweet, but in a particular way. If you have some great code in C++ and want to reuse it from Javascript on the web… well, there you go.

Building Terrier for the Web

We quickly had a Terrier SDK for Mobile when we started Wet Dog Weather. We’d previously worked on weather apps using an open-source toolkit (which we also own). Building back up the pieces we needed for mobile wasn’t too hard, but building it for the web was.

We had this mostly C++ mobile weather product. The part that does data display, fetching, and all that stuff was crazy good at its job. We have found all the corner cases and sanded down all the scratchy bits.

This complex engine worked well on iOS and Android, so we had a couple of choices when moving to the web. The most obvious was to rewrite it entirely in Javascript, which was an expensive proposition.

Thankfully, we went the other way, cross-compiling the core toolkit into WASM and then building a friendly Javascript layer on top. Web Assembly made this process much more efficient.

Mobile Set Us up With Good Habits

At that point, we were already deep into cross-platform development, having to support iOS and Android. Adding a third platform using LLVM and Emscripten was easier than you might think.

Once the configuration and build issues were addressed, the C++ changes weren’t too bad. For iOS, we had a reasonably fluid Swift/Objective-C/C++ boundary, but for Android, we were used to the iron wall of the Java Native Interface.

JNI guards the barrier between Java (or Kotlin) and C++. Getting past it on Android is deeply painful, and you try to avoid it as much as possible. This sets up some surprisingly healthy habits regarding the Javascript to WASM interface:

  • Bigger objects with large, well-defined interfaces
  • Instead of small objects, we used arrays of low-level types
  • As few callbacks into Java (or Javascript) as possible
  • Avoid loops between the two sides
  • Treat calling back and forth as costly

Once the C++ core was ported over, we built a somewhat weird and janky Javascript interface on top of it. Then, we built a nice, logical interface on top of that. That’s what we call Terrier for Web and what our developers see.

We’ve always known developers on any platform want their interfaces; on iOS, that’s Swift. On Android, it’s Kotlin and Java. It’s obviously Javascript on the web, so that was a natural fit.

Debugging is Meh

Tools for debugging our Javascript code are great! Usually, we bring up Chrome and step into the problem. We can also pull up client sites and examine their problems. I had no idea the modern web was so much fun to develop until we did this!

The Web Assembly portion is less fun. We use a lot of printf debugging and rely on our C++, which is very reliable and well-tested. That’s worked out fine, but it does mean we develop new functionality for mobile first, where we have the good debuggers, and then port over.

Better tools are available now and are definitely in the pipeline. Debugging is really the biggest gap in Web Assembly.

Is Web Assembly Good for All Projects?

We love Web Assembly and its ability to bring Terrier to the web quickly and efficiently.

  • Largely C++ code base
  • Debugged, well-understood, well tested
  • Already multi-platform
  • Already had a separate interface for each platform
  • It is an ideal use case for WASM.

If you have a toolkit that already works in Javascript, I’m not sure it makes much sense to switch to Web Assembly. Your JS developers probably won’t like it, and you’re trading easy debugging for… less easy.

If you’re starting something brand new, Web Assembly might make sense. If there’s a solid cross-platform requirement, perhaps. But keep in mind the cost of working this way.

Web Assembly is a pretty nifty tool with a rather specific use case once you dig into it. We had that use case, and it was brilliant.