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

Reply via email to