Defensive programming means writing code that expects things to go wrong. Instead of assuming inputs are valid and callers behave, defensive code validates its arguments, checks return values, and guards against states that “should never happen.” The goal is robustness: software that fails predictably and safely rather than corrupting data or limping along in a broken condition.
The Pragmatic Programmer captures the core habits in its tips. Tip 38, “Crash Early,” argues that a dead program normally does a lot less damage than a crippled one, so it is better to stop at the first sign of an impossible state. Tip 39, “Use Assertions to Prevent the Impossible,” recommends that if something genuinely cannot happen, an assertion should be there to ensure it does not, validating the assumptions the code is built on. Tip 37, “Design with Contracts,” frames the same idea as making each component’s obligations explicit.
Failing fast is central to this approach. When a function receives a value that violates its assumptions, raising an error immediately surfaces the bug close to its cause, where it is easy to diagnose, rather than letting it propagate into corrupted output far downstream.
Defensive programming overlaps heavily with secure coding. The SEI CERT coding standards, which the secure coding community maintains, codify many of the same rules around validating input and handling errors, because the same unchecked assumptions that cause crashes are often the ones attackers exploit. Done well, defensive code is both more reliable and harder to misuse.