write tests first, code later (TDD, test-driven development).
this only works if you have perfect knowledge of the domain problem and/or have infinite time. I don't have either of these.
working off an existing codebase:
- write tests for code you're happy with but need confidence about
- bad code gets split/refactored so it's easier to test
- 100% coverage is a myth/waste of time, choose your battles
any bug found shows a failure condition you couldn't think of when writing the code/tests, so, add a test for it, and keep it, so that it doesn't pop up again.
also, even if you're not doing full TDD, thinking about tests helps you figure out the right interfaces/module coupling/level of abstraction and avoiding global variables.