Monday, August 29, 2022
Failing nicely: what graceful degradation means for your app and its users
No one wants to think about their app failing. And in an ideal world, no one would have to. But with something as complex as the app development process, failures and breaks are sadly inevitable.
When this happens, how you deal with it is often more important than what actually went wrong. While you can't always protect your app from failure, there are ways to handle it gracefully and minimise the impact, and putting those in place can make a world of difference for you and your users.
Failure happens – and that's OK
People who are new to the software world often think failure is rare. They might think that if their development team have done their job properly and the coding is rock-solid, surely nothing in the app will ever break?
So when something does fail – and it will eventually – it’s a shock. More than that, it’s a huge embarrassment to see the app you’re so proud of throwing error messages at your users. Often firms want to circle the wagons, get the problem fixed as soon as possible, and hope no one noticed anything. But an app failure doesn't equal a business failure.
The best way to deal with those failures is to adopt a mature approach. No one sets out to make buggy applications. It's just that complex tech systems are chaotic, and no amount of app testing tools will catch everything. Half the time it’ll be a third party failure that was outside of your control anyway.
A mature approach also means telling your users when something’s gone wrong. If you try to fail silently they’ll just be stuck on an error screen with no idea you’re aware of the issue or that you’re working on a fix. By the time that fix comes, they’ve deleted you from their home screen with only a bad experience to remember you by.
Make the chance of failure part of your app design
The next step is to build with graceful degradation in mind. Big firms handle this particularly well. Typically they’ll build out a microservices architecture, which means having separate backend services to look after things like login, checkout, customer service and so on. If one of those backend systems breaks, then only one bit of functionality is lost rather than the entire service.
But those firms can do that because they have the resources to throw at multiple teams of backend developers. For start-ups and scale-ups, the cost of setting up that kind of software architecture, keeping it running and making it reliable is far too high.
Architectural design isn’t the only way to guard your system, though. You can also be smart about your API calls.
The traditional route for app structuring is to have a single API call that’s responsible for fetching all the items like the user’s news feed, their notifications, updates and suggestions.
If just one of those elements has an issue the whole thing breaks. But if you split those elements into separate API calls you can ensure that one failure doesn’t take out the rest of your core app features.
You probably won’t want a dedicated API call for every single element – making eight calls at the same time and waiting for eight responses comes with a significant performance cost. Instead, identify what your users want to see most from your app, and give that its own prioritised API call so that the core value of your app is always protected when another part of the app fails.
The bulk of the engineering focus can then go on making that first API call as reliable as possible. And that’s exactly what we did with Sole Retriever – an app that enables users to buy sneakers the moment they become available online.
For Sole Retriever’s target audience, there’s one element that’s more important than all the others: push notifications. A quick ping or buzz in a user’s pocket is what enables them to beat other sneakerheads rushing to purchase.
So when we built the app, we created a separate, dedicated service that deals with those push notifications and another that handles everything else. It’s an approach that definitely paid off for the brand. As one user review mildly put it: “ALLLLLWAYS ON POINT WITH THE NOTIFICATIONS 🔥🔥🔥🔥”
Navigate failures the way your users would want
Whatever kind of software architecture or API structure you put in place, ultimately the best way to fail gracefully is to always think about it from your users’ perspective.
For example in React and React Native you can take advantage of error boundaries. These effectively act like quarantines around all the components of your frontend, so if one of those components has an error it stays isolated rather than taking down the whole page.
That means if there’s a problem with one of your header components or a button, the worst that will happen is that it will render an error message. It might not look pretty, but app users won't care so long as the core functionality of the service is still working.
If you want to get creative, there are even ways to make failures feel fun for users. Like Google Chrome’s “no internet” page, which looks at first like a static image of a dinosaur but becomes a simple arcade game when you hit the space bar.
Instead of making the failure look as small as possible, Chrome draws attention to it in a way that almost makes you wish the internet wouldn’t come back. Google know there’s nothing they can do to fix someone’s bad Wi-Fi connection, but they can weather the break and turn it into a positive user experience.
For more on how to design the best user experiences, check out how to safeguard quality during post-MVP scaling or how effective wireframing can save you time and effort.
If you’re looking to get your app project off the ground, speak to us to see how we can help.