Assertions in Production Code?
Assertions are runtime tests put into code to perform a check that the logic of a program is correct. They are alternatively known as program invariants, or as part of contract programming. Assertions are not there to validate user input to a program. An example of an assertion might be a check that an array index is within the bounds of the array, or that a number that should be odd actually is odd, etc.
Asserts are common enough that languages like the D programming language have a special syntactical construct for them.
Asserts have proven to be very effective at finding logic bugs while debugging a program. But the question often comes up, what happens to the asserts in production code? Do the asserts stay in, or should they be removed? This was recently debated at length in comp.lang.c++.moderated. The arguments in favor of removing them were along the lines of:
- The production code will run faster.
- Professionally written production code is bug free, so there is no need for asserts.
- An assert firing causes the program to abort, which may not be permissible, may cause data loss, and looks unprofessional to the customer.
- The data being checked may not matter anyway, so why check it?
First let me explain a bit where I'm coming from. I started my engineering life working for an airframe manufacturer designing flight control systems for airliners. Failure of such systems will cause a crash where everybody dies. So the company (and us engineers) had a very powerful incentive to design a system that would not crash.
They had a very interesting approach to this (which is common in the aerospace industry). All parts are considered suspect, and all designs were evaluated on the basis of "what if this part fails?" If the answer was "the plane crashes" then the engineers went back to work.
In other words, the airplane can withstand the total failure of ANY part or system.
It applies not just to the hardware, but to the avionics software, as well. I won't go into the boring details, but even though the software is gone over line by line by lots of people, the software is STILL treated as if it can become possessed by evil at any moment and will try to crash the airplane. It's loaded up with self-checking software, self-checking hardware, other computers double-checking the answers, etc.
If someone arrived saying they could write software with perfect designs and perfect test coverage and so no backup, redundancy, or checking is required when it is flying, well, they won't be writing software for aerospace companies.
High reliability is not achieved by making perfect designs, it is achieved by making designs that are tolerant of failure. Runtime checking is essential to this, as when a fault is detected the program can go into a controlled state doing things like:
- aborting before more harm is done
- alerting the user that the results are not reliable
- saving any work in process
- engaging any backup system
- restarting the system from a known good state
- going into a 'safe mode' to await further instructions
I find these options far preferable than going into an unknown state and praying. Would you engage an airplane autopilot with software with no runtime checking? Would you fire a missile with a flight control computer in it with no double-checks on crazy control outputs? Would you want a defibrillator applied to you with no double checks on the voltage applied? How about that X-ray machine intensity?
I don't care how smart you are and how good you believe your testing is. I want a backup, and so does everyone else whose life depends on a computer. It's why any pilot who lives to old age doesn't believe his gas gauge and, before flight, goes out, unscrews the cap, and puts a stick in the gas tank to check the gas. The ones that don't, like John Denver, you read about in the paper the next day.