NetNewsWire Crash Assessment
Daniel Pasco

I was recently badly burned by a similar situation: an unnecessary assertion fired in production code, crashing every user of that version of the app. The assertion was even triggered by pushing a button on our server, which seemed entirely innocuous until my phone buzzed in my pocket, confronting me with the horrifying sight of a Crashlytics email freaking out because a thousand iPads had all just cried out in terror, and were suddenly silenced.

In my case, however, the assertions weren't enabled accidentally. I deliberately ship with assertions on. Even this nightmare scenario didn't change that, though now I am more judicious about when I assert.

I ship with assertions enabled because an assertion states, "I am 100% certain this condition will never be false, and will write the following logic assuming it's not false." A triggered assertion means that the app has gotten into a state the programmer thought was impossible to enter, and that could only have happened because of a programmer error. In other words: a triggered assertion means there's a bug in my code. If I turn off assertions in release builds, that doesn't mean that what would have triggered an assertion magically stops being a bug, it means that code will execute in a state that it assumes won't happen, which is a perfect recipe for user data corruption. And user data corruption can easily end up crashing down the line anyway, but now I have no idea why the data got corrupted to begin with.

I fully respect when apps decide to ship with assertions turned off, I think it's a perfectly reasonable decision to arrive at, but I regard it as a tradeoff of an increased risk of crashing with assertions enabled versus an increased risk of corrupting user data with assertions disabled, and since corrupt data tends to be harder to debug than an assertion crash, I prefer to instead explode at the first sign of trouble.

The assertion that burned me—as I said before—was unnecessary. The logic that followed was perfectly capable of handling the situation the assertion guarded against, so I feel the problem there was asserting inappropriately and too greedily, not the fact that assertions were enabled. It's very rare for my enabled assertions to actually trigger in production code, and except for this one really bad situation the live crashes always caught bugs that otherwise would have been far more difficult to identify and fix. From the metrics I've been able to find to compare to, the crash rates of the apps I work on are far below those of average apps, and I credit—perhaps paradoxically—how many live assertions I ship with for a non-trivial part of that. My code has gotten more stable as it has gotten stricter about the states it allows itself to operate in.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.