Why sometimes we shouldn’t avoid crashes of mobile apps? When should we? Is it a good idea to “try catch” the whole application’s code?

To Crash, or Not to Crash, That Is the Question. In our early careers, we see crashes as a terrible thing. We had failed and our code crashed the application. We get used to seeing it. We learn how to avoid common mistakes. We learn how to deal with exceptions to not let applications crash. We see crashes less often. We dream about the time when our code is flawless and when the application has no crashes at all. It is always a good thing during an app development process. Or is it?

“Try catch” the whole code

The idea to “try catch” the whole code might seem as a good idea for young app developers. Cheap and easy way to get rid of crashes. Then we add some code to show errors to the user. Here we go, an application without crashes! The dream came true! Let’s see what reviews our perfect app gets. Oh… Why such a low score, we have no crashes! And we didn’t need any testing, because we can’t have any crashes! Okay, let’s study what happened:

  1. Users see error screens a lot. There is no retry button, so users just quit the application and never come back.
  2. I, as a developer, have harder times finding out what happened. Adding logs helps a bit, but navigating between classes to fix something takes some time.
Mobile development - To Crash, or Not to Crash

“Try catch” each screen

Attempting to “try catch” the whole code was a bad idea. Let’s try “try catch” for each screen with retry action! This way, the user can refresh the screen and its data if something goes wrong. We also benefit from easier crash tracking, because we know on which screen crash has happened. Great, updated application, users will love it! Let’s check reviews. Okay, it is better, but there are still problems. 

  1. Users can refresh the screen and continue to use the application.
  2. I, as a developer, can track crashes much easier.
  3. Reported errors by users are less frequent, but at the same time, they seem to be new types! Users hate it because after retrying actions on error screens, the application has started to behave abnormally!

Allow app crashes for all cases

“Try catch” for each screen worked better, but there are issues that are hard to track and fix. Retrying actions after catching errors allowed users to use the application normally. But at the same time, long-lived variables were affected and the application started to behave differently. How about we let the application crash instead, so the app will reset and the user will be able to use it normally? Let’s check reviews.

  1. Users can’t retry after errors. Application crashes and they start from a fresh state.
  2. There is a huge amount of reports of an application being unstable, users hate the experience.
  3. Application works after the restart and allows users to use the application instead of being stuck! That looks like some kind of progress.
Mobile development - To Crash, or Not to Crash

What to do then?

To get the full benefit of “evil” crashes, we have to allow crashes as a tool to restart the application, to avoid users being stuck. At the same time, we have to limit crashes to the minimum. Crashes are annoying, so it should be a last resort to help users.

When we should catch errors and handle them

If we expect some error to occur, we can try to catch the error. Then we can either retry the action automatically or show an error message with a possible retry button. When we do a network call we can expect that something fails in between. Maybe there will be a network error? Maybe some API will fail to deliver proper data? Will some SDK report a problem with the hardware? Those are the cases we can expect to happen. It is not a random problem. We can actually be prepared to handle those situations and let the application recover.

When we should allow mobile apps to crash

As opposed to the advice above – if we don’t expect errors to occur, especially in our code, then we shouldn’t try to catch those errors. There are two reasons to don’t do that:

Doing so is too hard to handle errors properly. There might be millions of reasons why our application crashes. Improperly handled errors can influence an application’s behavior, which might be a new source of bugs or can make users stuck.

Because of the above, crashes are beneficial for users. After the crash, the application gets restarted. A fresh state means the user follows a path that got implemented, so there is less chance of a bug happening.

Crashing is also good for testers

Crashing is also a great way to indicate there is some problem within the application for QA. Not all testers read or understand logs. But they for sure understand that crashing is always something that shouldn’t happen. Application that crashes makes QA’s work faster, and it is easy to catch any unexpected states of the mobile app. The result is more QA’s time on other issues and higher application quality.

Mobile development - To Crash, or Not to Crash

Tips on how to proceed with exception handling

  1. Kotlin’s nullability is your friend. Migrate Java to Kotlin to make it much easier to avoid null pointer exceptions.
  2. Don’t be afraid to use requireNotNull or Kotlin’s not-null assertion operator (!!). If you know that this value is not null, but the type is nullable, not-null assertion is better than handling a null path when we know it shouldn’t be possible. If the value is null and it shouldn’t, then the application will crash. It is okay as the application is not expected to behave in such a way.
  3. Migrate GSON to Moshi or Kotlin Serializer (the latter preferred). GSON doesn’t respect kotlin’s nullability by default. GSON allows not nullable fields to be null. If such a field is used inside the application we can get a null pointer exception, which is not an obvious issue. Moshi and Kotlin serializers support kotlin’s nullability and throw exceptions during deserializing when null is not expected. Due to our handling of network call errors, the application will not crash and during development time, it will save us plenty of time looking for the source of error.
  4. If the function can throw SpecificException then catch SpecificException only, not Exception. If there is an exception that you don’t expect to happen, the application should crash.
  5. Prefer returning Kotlin’s sealed classes instead of throwing errors. It is much easier to forget handling errors than to handle returned sealed classes. If a third-party code throws an exception, map the result and exception into a sealed class. This will help to handle errors a lot.

Contact

Do you want to find out more about mobile development?

Talk to us!

Snippet tip

If you want to avoid throwing exceptions, you can use the below snippet to wrap the result.

sealed class Result<T> {
    data class Success<T>(val data : T) : Result<T>()
    data class Failure<T>(val exception : Exception) : Result<T>()
}

Mobile application crash – a necessary evil

We hate app crashes. Users hate crashes. But crashes are useful tools. We should treat them as a necessary evil – let the application crash and then fix it in the next build.

Let the application crash when something we don’t expect happens. Handle errors when we can expect them to happen.