There is a lot of debate surrounding whether assertions are a good idea or not. There is definitely some good arguments to be made from either side. I'm all for assertions if they are being used appropriately.

1. Assertions Halt The Application

Most languages have native support for what is usually an assert() function. It checks some boolean condition, if it's false (or, otherwise not true) it reports the error and immediately kills the running application.

Wow, that sounds dangerous! It is... for good reason. Consider this example in PHP:

function foo($o) {
assert(is_object($o));
return $o->bar;
}

If $o is not an object the assertion will report the error and stop the running application. If we allowed the code to continue the application will produce a fatal error and die anyway.

We caught the fact that $o was not an object just before the fatal error. Not super helpful since it would be easy to determine from the fatal error what had happened. However, what's much more important is how we got here in the first place. A stack trace can only tell you so much. It often won't have enough information about why $o is not an object without digging through a lot of code, tracing back and usually making a few educated guesses.

Let's consider it from another point of view:

function decodeObject($json) {
$o = json_decode($json);
assert(is_object($o));
return $o;
}

There is one important difference here. We are catching the bad application state when it occurs, rather than when it is used, or before we know what is going to happen with it. Without this early check the code may go on for a long time before the actual error occurs. The stack trace may not even be connected to the original code if your using some asynchronous process. Very difficult and time consuming to work backward from.

I know what you're thinking, "isn't this just another kind of error checking?" Actually, no, this is what causes a lot of the confusion about assertions, in my option. Assertions are reserved for conditions that you know put the application into a state that is not recoverable and it should report the error with as much detail as possible and halt execution.

2. Assertions Should Never Be Caught

It's important that assertions are never be caught by traditional error handling of the language, such as catching exceptions. If they were to be caught it would allow the bad state to continue, or worse, change the expected flow of the code.

This means that assertions must be reserved for special conditions where you know the application would not be able to proceed - a non-recoverable kind of error.

However, it's common (and I believe a good idea) to have assertions disabled in production (still logging the error, but not halting the application), and use them to be overprotective in development where it may not be a fatal error in all cases.

Either way assertions should not be downgraded to exceptions for the same reasons above.

3. Capture As Much Detail As Possible

Depending on the language, assertions can report different levels of information. While it's important that we catch the bad state early, it's also important that we capture as much information as possible so that we can understand why it failed.

Let's see what PHP 7 does with this example:

decodeObject('123');

Should output something similar to:

assert(): assert(is_object($o)) failed on line number 5

This wouldn't tell us much in the logs. However, most languages let you add extra details, like a message or values to the assertion as a second argument:

assert(is_object($o), $json);

Now we have a descriptive error (the formatting may seem weird but you can tweak that with the assertion options):

assert(): 123 failed on line number 5

The complete log entry will also contain the stack trace that should help very much with diagnosing the error.

In Summary

  1. Assertions are a way to locate when an application is in a bad state, before an indirect and much more cryptic error occurs.
  2. It's often a good idea to be overprotective in development and keep an eye on any failures in production, separately from generic error logs.
  3. Assertions should not be caught like other traditional errors and should always immediately halt the execution of the app if they are enabled.
  4. Assertion failures should contain as much detail as possible to help diagnose why the failure occurred later. This can include the stack trace, variable values and other context (such as the logged in user).

Here are the PHP assertion options to work as described above. These would go into your bootstrap:

assert_options(ASSERT_ACTIVE, true);
assert_options(ASSERT_BAIL, !isProductionEnvironment());