How Clubhouse.io used Objective-C + the Sentry React Native Integration for Post-Launch Error Tracking
In A Comedy of Errors, we talk to engineers about the weirdest, worst, and most interesting application and infrastructure issues they’ve encountered (and resolved) over the years. This week, we hear from Eli Perkins, Mobile Engineer at Clubhouse. Clubhouse is a project management platform that makes it simple for software teams to relate how their everyday tasks are contributing towards a larger goal.
I'm a Mobile Engineer at Clubhouse, which is project management software focused on developers. In addition to using a mobile performance monitoring tool like Sentry to monitor errors on our mobile app, Clubhouse also provides a community-maintained integration that connects Sentry crash reports to Clubhouse Stories.
For the past two years, my work has focused on translating the platform’s web features to a mobile experience with an emphasis on figuring out what that looks like in design and implementation stages. We launched the mobile app in February, so it's been really exciting.
Prior to launch, the biggest struggle was figuring out specific changes to make to the product and how to handle it on the mobile side. Clubhouse has been around for two years now, and naturally, there have been a lot of changes during that time. Understandably, we needed to read through the web codebase, figure out where data might be a little funky, and massage a bit of data to make it work. We also introduced a GraphQL layer to our stack, just for the mobile app.
Finding solutions to the problems we have with new technology has been the most fun part of the process. One unique aspect of Clubhouse is that we're not completely risk averse; we have the opportunity to try new things and adopt the right technology that fits our needs.
The closer we got to launching the mobile app, the more nervous I was about making sure the app would be scalable. Continued monitoring proved to be extremely useful on this front. By throwing errors and spiking graphs, Sentry’s reports helped ensure everything was working properly and prevented a product-wide crash due to some unforeseen issue. Fortunately for everyone involved, the launch was fairly clean.
Once we implemented error handling, it was only a matter of minutes before we could look at that specific data and see what was actually going on.
However, we did have one instance (there has to be one, right?) where the data supplied from our GraphQL server caused our mobile app to render an incomplete sentence. We were missing the title, so it was creating an incomplete sentence, like Eli Perkins opened up a pull request ON. In this case, there was no indication of what it was acting on. Once we implemented error handling, it was only a matter of minutes before we could look at that specific data and see what was actually going on.
The addition of Sentry allowed us to pinpoint and locate the problem, tracing the data all the way to the part of the stack causing an issue. We sifted through data the mobile app and GraphQL received, as well as how the server and our database responded. We audited the nullability of the values in our GraphQL layer, such that all our clients knew how to put together a complete sentence. Sentry let us capture that moment in time, and look at the data closely to see what we were missing.
We use the Sentry React Native integration on our apps, which shows us the JavaScript and Objective C stack traces merged together. This has been really cool.
Error tracking has also been useful post-launch. We have a lot of different relationships between our data — a story has a project, an owner, an epic, and so on. The app has to do a little bit of coordinating to retrieve all that data from our servers. We found that the app was crashing for certain users when they switched between their organizations. For example, say someone belonged to Organization A and Organization B. If they started in A, switched to B, and then quickly went to a story, the app would crash because the data wasn't loading yet.
As it turns out, we were attempting to access a property on a project, but the project wasn’t yet loaded in memory. We're using the Sentry React Native integration on our apps, which shows us the JavaScript and Objective C stack traces merged together. This has been really cool — when the app crashed, we walked through this stacktrace and saw exactly why it crashed. We were throwing an Objective C exception, but we saw exactly where the error was on a specific line of JavaScript and where things were generative. We pinpointed that and said, Okay, now we need to create a new strategy so that all of our data is loaded before we show this screen.
With this in mind, we put together a loading mechanism that would fetch all that data. If the data wasn't there yet, the app wouldn't allow the story to render while it waited for the data to load. We definitely used every available feature and tool we had to get all those pieces lined up.