1) Use the best language you can get away with. This means using a language that eliminates entire classes of run-time errors via some or all of:
a) Strong typing
b) Static typing
c) Managed memory
d) Immutable data
2) Assume that your code will be maintained by somebody who doesn't know your programming language as well as you do.3) Use static and dynamic assertions liberally.
4) Ease debugging. Have great formatted dumps of your internal data structures, great internal consistency checking, and great logging. Automate problem isolation, too: for example, in an optimizing compiler, at each point where a discretionary change is about to be made, call a function that logs the change, increments a counter, and returns false if the counter is past a limit that you can set in the environment; this allows an automated bisection analysis to immediately find the change that broke a test program.
5) Regression tests. Once you fix a bug, make sure that your test suite will notice recrudescence.
6) Don't hire or retain sloppy programmers.