The good news is that we have a work-around for the affected party, but we have yet to reproduce the problem on anyone else's machine. And of course, if you can't reproduce it, it's difficult-- although perhaps not impossible -- to fix it.
In terms of general strategies for creating high quality / low bug-count software, the following have worked well for me:
1. Design By Contract (DBC): Read Object-Oriented Software Construction (2nd ed.) by Bertrand Meyer and become a much better programmer. Although you need the not-widely-used Eiffel language to get the full benefit of this approach you can get 80% in any language by implementing cheap pre-condition and post-condition library. It allows you to write down what you think you know about the program state and allows the computer to catch errors early and close to point-of-failure. The name of the game is localizing the error.
2. eXtreme Programming (XP)Practices: Especially:
- Pair programming: Two heads are often better than one
- Test-Driven Design/Development (TDD): Overlaps somewhat with DBC, but very useful (write the test, make it pass, re-factor). Note: I tend to use DBC to test the pre-conditions, and TDD to sample the post-conditions, to reduce the overlap.
- Continuous Integration: Saves you from "merge hell" when working on a team
- Sustainable pace: Working long hours will damage the code-base
- "Don't Repeat Yourself" (eliminate duplication)
- Find the right abstractions (unify and split as needed)
5. Good diagnostics: If a bug does occur to a user make it easy for them to send you an error report with the information that you want: Error-code, OS version, app. version, stack-trace etc. With rich diagnostics you may be able to fix some errors that you can't necessarily reproduce.
6. Learn: Look into higher-level and academic languages for rich ideas (e.g. Eiffel, OCaml, Haskell, Lisp, Prolog, etc.) and see if you can use them to simplify your code.
What I don't use so much is exceptions and defensive-programming. Serious users of DBC and TDD both find that exceptions are needed a lot less often than you might think. Defensive-programming is trumped by DBC.
Patterns are useful, especially for talking about software design chunks, but they aren't the key to my approach.
"There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies." — C.A.R. Hoare.