In design by contract, why preconditions should be ensured by a client and postconditions - by a supplier?

softwareengineering.stackexchange https://softwareengineering.stackexchange.com/questions/332925

  •  29-12-2020
  •  | 
  •  

Question

I'd heard about Design by Contract a long time ago and always was confused by this question. The approach uses real-world client-supplier analogy to describe caller-callee relationships. It stays, that if a client ensures preconditions before calling a supplier, the supplier will get the benefits by avoiding preconditions check; and, on the other hand, if supplier ensures postconditions, the client will get benefit by avoiding checking those; everyone is happy. That's what is written in Wikipedia, on EiffelSoftware website and in billions of other places.

Example

But. The world is cruel. And in most cases in the real world everyone prefers to check what he got for work instead of being sure that the work is done correctly. Even in the example above, we are checked in the airport for the preconditions (ticket, baggage, etc), the supplier doesn't trust us. And in the end of the fly, we want to be sure that we're really in Chicago and our baggage hasn't been lost.

So, what the benefits of checks made by a client instead of a supplier? I see no difference. Is the analogy with the real world is bad or did I just missed something? Could we swap checkers of postconditions and preconditions and still call it design by contract?

Was it helpful?

Solution

The reason that preconditions should be checked by the client is that the client is in a better position to collect or solicit any missing information because (presumably) it is better able to communicate with the user. By the time the supplier gets involved, all it can do is throw an error and abort processing, since it doesn't know where any missing information should come from.

Postconditions should be handled by the supplier to alleviate the effort required to write a client. If the client is guaranteed that (for example) a particular value will never be null, or will only contain values within a specified range, it enables the client to simply process the values instead of having to validate them first.

OTHER TIPS

Like most analogies it isn't universally applicable. It's really meant to give you permission not to feel you must always check everything at every step. However, it's not saying that if the check has been done once it should never be done again.

Between those extremes is where trust comes in. If you never expect to be called by anything else trusting your caller may make sense. If you're a library, trusting your caller is insane.

You seem to be advocating the library attitude of never trusting your caller. The benefits are assurance of valid input and easy to decipher error messages. The cost, in increasing order of significance, is redundant checks impacting: performance, code writing, and code reading. The worst is conceptual.

Thinking of every object boundary as a library boundary comes at a cost. I don't design interfaces the same across a library boundary as I do within the application. It's the same with validation.

If all your objects lead interesting lives the library attitude is valid. But if I have a quite little object that's only used by this one caller I trust you'll forgive me for assuming some checks, and some work, have already been done.

It's also worth noting that each object should be concerned with it's own responsibilities. It's my callers job to give me what I need. But not to decide what I need. Thus it's not reasonable for the airplane to expect the taxi to check the size and weight of your bags the same way the airport would. These are different relationships.

You're correct. The analogy isn't a particularly good one. That may be part of the difficulty with the idea of design by contract: it's so rare in real life to be able to wholly rely on the contract that both parties almost always do the pre/post/invariant checks themselves.

The critical idea in a design by contract language is that, if you can state the conditions, the compiler can enforce them. This has the benefit that they only need to be done once as well as the, possibly more important, benefit that they will definitely be done.

Licensed under: CC-BY-SA with attribution
scroll top