[racket] Code that double checks is good, bad, other?
Here is an answer that's not a book but it should be one.
1. If you write an exported function that looks like this:
(define (workhorse x)
(validate
validate
validate
validate x ...)
(compute with x ...))
I recommend that you factor out the validation into a contract:
(provide
(contract-out
(->i ([x (lambda (x)
(validate
validate
validate
validate x ...))])
...)
(define (workhorse x)
(compute with x ...)
It is extremely likely that whoever uses workhorse needs to know about these checks, because they are a part of the interface. Put them there, and only there.
2. If you are working on a chain of module and except for the top and bottom one, none has contact with the external world, validate values that flow thru the chain once: on the way in or out. Skip checks everywhere else.
3. For the top and bottom value, write the contracts that you want (for the supplier) and weaken the contract that you promise (the client) and in between trust yourself.
4. If you have a type system, use it instead of 3. As Neil says, you get some of these checks for free (during compile time) so do them.
-- Matthias