"If you ask most developers on the street 'why do we test code' you'll get an answer something like: 'to find bugs!' Finding bugs is good, but I think finding bugs is a happy side effect of writing tests. [...]
Writing tests is one of those necessary things but it exhibits diminishing returns. The first 100 hours you spend writing tests are probably going to be more effective in terms of improving your confidence in the code than the 100 hours from 1000-1100. [...]
A better way to think about the kind of testing that we do is not that we're looking for bugs it's that we're looking to buy confidence. [...]
Writing tests is a form of buying confidence that exhibits diminishing returns.
Code review does the same thing. [...]
And if you try to apply portfolio theory to optimizing the QA budget [and] you observe that both of these buy you confidence with diminishing returns and they're uncorrelated then the optimal portfolio is to have some mix of testing and code review rather than putting all your eggs in one basket or the other.
Static analysis yet a third thing we can do [...] that tends to find different kinds of bugs than either testing or code review. So it's something that should be part of everybody's development lifecycle, ererybody's arsenal, everybody's toolkit."
I'm a huge fan of FindBugs and other static analysis tools I wish there were more ways (ie. a richer set of annotations) to make things in Python (and even in Java) more explicit, so that these tools could catch stupid mistakes for almost free and immediately rather than letting them slip through and manifest as hard to find bugs further down the road.