Search code examples
robustness

Best Practices for Robustness


I just came across this question about initializing local variables. Many of the answers debated simplicity/readability vs. robustness. As a developer of (remotely deployed) embedded systems, I always favor robustness and tend to follow several seemingly conflicting rules:

  • Handle every error to the best of your ability in a way that allows the device to continue running.

  • Design the code to fail as soon as possible after a programming or fatal error occurs.

We've all been trained to validate input to prevent the device from breaking as a result of user (or other external) input; always assume data may be invalid and test it accordingly.

What other specific practices do you follow to ensure robustness? Examples are helpful, but I'm also interested in techniques that are universally applicable.


Solution

  • I implement a variety of methods to prevent and recover from errors:

    1) Handle all exceptions. As you stated, "handle every error". If a user clicks a button on a form, there should be no possibility of the application just disappearing ("poof") from an unhandled exception. For that reason, I wrap event handlers with a generic try catch.

    2) Log errors with full stack trace. When I rethrow an exception I always create a new one and add the caught exception as an inner exception. My logging code unwraps the messages recursively which gives a little more detail than I'd have otherwise.

    3) Decide whether your classes are going to be reusable or not. If not document it. Consider implementing an interface in your code, something like IRestartable or IReusable. Any object not implementing it must be thrown away after it's used once.

    4) Never assume thread safety. I've learned the hard way that .NET is extremely multi-threaded. Many events are handled on arbitrary threads. A given app written in .NET could have many simultaneous threads executing and not have a single line of code explicitly creating one.

    5) Keep variable scope as narrow as possible. Instantiate objects near where they are used instead of in a large block at the beginning of a method. You'll potentially shorten the life of the objects and you won't forget about unneeded or reused variables sitting in a huge block at the top of the class or method.

    5) Simple, but I still see it happening. Avoid globals like the plague. I've seen code with hundreds of unused/reused variables. It was a mess to figure out and refactor.