There's a simple rule in the world of contract engineering: * as a client, demand the strongest possible promise from the serving module * as a server, promise as little as you can get away with
-- Matthias On Oct 4, 2014, at 3:42 PM, Sean Kanaley wrote: > What do you mean by "weaken" in #3? I presume you mean use a more general > type. Is this to allow for flexibility in future iterations? Promising any/c > instead of void? ? > > On Sat, Oct 4, 2014 at 3:04 PM, Matthias Felleisen <matth...@ccs.neu.edu> > wrote: > > 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 > > > > > >
____________________ Racket Users list: http://lists.racket-lang.org/users