Introducing Belay: Robust Error-Handling for Kotlin and Android

Nathanael
Specto
Published in
3 min readDec 3, 2020

Introducing Belay: github.com/specto-dev/belay

Early this year I started working at Specto, a startup tackling performance monitoring for mobile apps. I was the first Android engineer there, and so got to start with a fresh Android project. One of the best feelings I know. 🌱

As I built our Android SDK, measuring application performance turned out to be my second priority. My first, most important task, was to avoid crashing our customers’ applications at all cost. You may have heard about the Facebook SDK causing apps to crash on launch. Not a good look. And yet, I empathize: writing software is hard. I knew I needed a deliberate approach to reduce the chance of a critical incident happening.

Part of my plan was to write assertions: conditional statements whose sole purpose is to check that the program is in a valid state (for example checking function inputs and outputs). If the program detects itself to be in an invalid state, it deliberately triggers a crash to notify the developer. Assertions are typically disabled in production to avoid such crashes, with the hope that unexpected states won’t prove critical and result in a crash of their own:

Unfortunately, invalid states may be possible but never manifest until an application has been shipped to production. Applications that wish to be truly robust can complement assertions with error-handling code that will run in production, where the assertions are disabled:

We can rest easy knowing that countBananas will never return an invalid count. But our code is redundant: the same condition appears twice. And it is quite verbose, especially since a single function could have multiple assertions and potential errors to handle. Working with assertions is also not particularly straightforward—do you know how to enable or disable them for Kotlin?

I had to StackOverflow it just now: they are disabled by default and can be enabled by running the JVM with the -ea option. I’d have to keep searching to figure out exactly how to do that. 😅

I suspect those reasons are part of why assertions and error-handling code are not always widely used, even in consumer applications where crashing is a deadly sin. I certainly wasn’t looking forward to having to write both, and that is what led me to create Belay, a Kotlin library which leverages powerful language features to combine assertions and error-handling into one:

It includes variants for all sorts of scenarios, here are just a few examples.

No Error-Handling Needed

Smart Casting

Expectation Blocks

Custom Expectation Handlers

The global behavior is for you to configure, that is, what should happen when an arbitrary expectation fails? For example, you might throw an exception in debug mode, thus converting all expectations into assertions, and silently log the error in production, to fix it at a later time:

The library is open sourced and fully documented on GitHub. It is published in Maven Central:

I look forward to your feedback and contributions. The library is already used extensively by the Specto Android SDK. If you’re interested in performance monitoring for your Android or iOS apps I suggest you check us out!

Thanks for reading. 😊

--

--