Favorite (Clever) Defensive Programming Best Practices [closed]

If you had to choose your Favorite (clever) techniques for defensive coding, what would they be? Although my current languages are Java and Objective-C (with a background in C++), feel free to answer in any language. Emphasis here would be on clever defensive techniques other than those that 70%+ of us here already know about. So now it is time to dig deep into your bag of tricks.

In other words try to think of other than this uninteresting example:

  • if(5 == x) instead of if(x == 5): to avoid unintended assignment

Here are some examples of some intriguing best defensive programming practices (language-specific examples are in Java):

- Lock down your variables until you know that you need to change them

That is, you can declare all variables final until you know that you will need to change it, at which point you can remove the final. One commonly unknown fact is that this is also valid for method params:

public void foo(final int arg) { /* Stuff Here */ }

- When something bad happens, leave a trail of evidence behind

There are a number of things you can do when you have an exception: obviously logging it and performing some cleanup would be a few. But you can also leave a trail of evidence (e.g. setting variables to sentinel values like "UNABLE TO LOAD FILE" or 99999 would be useful in the debugger, in case you happen to blow past an exception catch-block).

- When it comes to consistency: the devil is in the details

Be as consistent with the other libraries that you are using. For example, in Java, if you are creating a method that extracts a range of values make the lower bound inclusive and the upper bound exclusive. This will make it consistent with methods like String.substring(start, end) which operates in the same way. You'll find all of these type of methods in the Sun JDK to behave this way as it makes various operations including iteration of elements consistent with arrays, where the indices are from Zero (inclusive) to the length of the array (exclusive).

So what are some favorite defensive practices of yours?

Update: If you haven't already, feel free to chime in. I am giving a chance for more responses to come in before I choose the official answer.


Solution 1:

In c++, I once liked redefining new so that it provided some extra memory to catch fence-post errors.

Currently, I prefer avoiding defensive programming in favor of Test Driven Development. If you catch errors quickly and externally, you don't need to muddy-up your code with defensive maneuvers, your code is DRY-er and you wind-up with fewer errors that you have to defend against.

As WikiKnowledge Wrote:

Avoid Defensive Programming, Fail Fast Instead.

By defensive programming I mean the habit of writing code that attempts to compensate for some failure in the data, of writing code that assumes that callers might provide data that doesn't conform to the contract between caller and subroutine and that the subroutine must somehow cope with it.

Solution 2:

SQL

When I have to delete data, I write

select *    
--delete    
From mytable    
Where ...

When I run it, I will know if I forgot or botched the where clause. I have a safety. If everything is fine, I highlight everything after the '--' comment tokens, and run it.

Edit: if I'm deleting a lot of data, I will use count(*) instead of just *

Solution 3:

Allocate a reasonable chunk of memory when the application starts - I think Steve McConnell referred to this as a memory parachute in Code Complete.

This can be used in case something serious goes wrong and you are required to terminate.

Allocating this memory up-front provides you with a safety-net, as you can free it up and then use the available memory to do the following:

  • Save all the persistent data
  • Close all the appropriate files
  • Write error messages to a log file
  • Present a meaningful error to the user

Solution 4:

In every switch statement that doesn't have a default case, I add a case that aborts the program with an error message.

#define INVALID_SWITCH_VALUE 0

switch (x) {
case 1:
  // ...
  break;
case 2:
  // ...
  break;
case 3:
  // ...
  break;
default:
  assert(INVALID_SWITCH_VALUE);
}