On Assertions
Discovering the proper use of assertions has been fruitful for my craft, this summary tries to compress why I find them vital.
A common misstep
I remember being puzzled by the assert macro during my first steps in programming. Why on earth would I want to crash my program anywhere I could
produce a boolean expression? They're also either absent from or maligned by most of the educational material I ran into; so I simply forgot about it
for a while.
It is imperative to study the work of your betters to improve; real code, not textbooks. It didn't take long to find out that quality code from is plagued with them, and they even come up in the the famous NASA rules. This article was a pivotal influence for me . The sqlite's website is a goldmine, I owe a lot to D. Richard Hipp's code and insights in system design.
Why Assert
The goal of assertions is to catch errors; that is, programming errors .
I've found the hierarchy of fault error failure very
illuminating for what is usually a deeply equivocal subject.
They are a fact of life, so our programming strategy had better account for them.
Asserts develop naturally with your code.
Easy to add by local reasoning, they join to form a net of constraints for the whole system. Errors are are what you did not think about it, this is how to you catch them. They multiply the effectiveness of any test or fuzzing suite You get value from your tests mostly when they fail, increasing their chance to do so is good.
They improve your understanding of your program
Not only they're live documentation, you will quickly find out about holes in your assumptions. An assertion triggering in a staging environment can save you weeks of bikeshedding! They also train you into thinking more clearly about correctness and establishing constraints . Great piece on clarity and correctness: Little Proofs
A liveness bug is preferable to a correctness bug
For most systems, it is better to crash than to unpredictably continue under broken state. That assertions should be disabled in release builds is a thought terminating cliché.
Strong types and assertions are not exclusive.
Most assertions are just a way to restrict the input set of a function: which is precisely the role of types. Strong types provide much stronger guarantees of correctness than runtime checks. Relying on strong types will often rule out the possibility of any programming errors.
Assertions also break the rule of API design that strives to keep control flow in the hands of the caller , a style that's facilitated by
a type system.
You can convince yourself by enrolling for a few months in a Java shop.
So why should we ever consider assertions?
The first reason is economical: software development is often an exploratory endeavour. You rarely one-shot the proper design, the functional specification is likely
to change as the product matures. Types work by adding friction, and mostly get in your way when you need to refactor the most. As the program matures, the frontiers that
experience helped to discover are slowly baked into the type system.
The second reason stands as an exception to our control flow rule provided above: In some extreme circumstances, the cost of the caller code poorly managing managing the error is high enough that it's safer to let the callee kill the program .
Most programs do not operate in a domain liable to such costs, I know. I advance this argument against the most ideallistic views on type safety. Proven critical systems manage both types and runtime checks.
My expectations for an assertion function
None of this means you're restricted to your language's default assert. I often build mine in whatever environment I need to work on.
- Multiple levels Distinguishing between slow and fast assertions has been good enough for me. Fast assertions are not turned off in production .
- Behaviour hooks Although it is the more likely setup, compiling them away and crashing the program are not the only options. We might want to turn our slow assertions into events for our metrics, pop up a crash reporter window...
- Proximity It should be useful for actual debugging; the closer to the actual frame that triggered the assertion, the better. It is also common for me to instrument the code with them just for debugging purposes, much faster than adding printfs!
You are always testing in production whether you like it or not.