Bill Venners has an interesting blog with a lot of interesting comments “Sloppy and Forgiving versus Strict Systems“. The subject matter is interesting because it touches on issues of interoperability, from a theoretical as well as pragmatic point of view.
First, the theoretical, one poster mentioned a quote by Jon Postel, (actually the poster wrote the quote incorrectly). Postel studied network protocol design and he said:
”Be liberal in what you accept, and conservative in what you send”
Betrand Meyer defined something similar, but more formally:
- An overriding method may [only] weaken the precondition. This means that the overriding precondition should be logically “or-ed” with the overridden precondition.
- An overriding method may [only] strengthen the postcondition. This means that the overriding postcondition should be logically “and-ed” with the overridden postcondition.
- A derived class invariant should be logically “and-ed” with its base class invariant.
In essence, implementations may relax the requirements on its inputs and can be stricter on the conditions of its outputs. Jon Postel gave a general guideline, Meyer applied it to design by contract, the principle holds true for interoperable design.
Now, for the pragmatics. There’s a principle that in effect says that “the higher the degrees of freedom, the more complex the system” (well I don’t know who said this). Anyway, it’s more complicated to write an implementation based on a “liberal” specification, than one that is strict.
It’s just like those questions on “Who wants to be a Millionaire?”, its easier to answer a question like “Who did this?” than a question like “Who did NOT do this?”. The former, you only need to know the right choice. The later, you have to know that answer for all choices. So pragamatically, writing a liberal consumer is just harder to do. However, as we shall see later, reality tells us otherwise, there are many liberal consumers that exist in the HTML and RSS world.
Why then are there so many sloppy producers? Why don’t producers follow strict implementations of a specification, afterall it isn’t as hard to implement? Wouldn’t this solve the all the problems, make life easier for the person writing the consumer? Unfortunately, reality is different from theory.
How does one verify compliance with a specification? Recall the XP principle “If a feature doesn’t have a test, then it doesn’t exist”, well that applies all too true for specifications too. Unfortunately, most specifications don’t come with a compliance test, or even worse even a reference implementation. In the absence of this test, de facto implementations emerge, becoming proxies for the original specification. The original specification is then subverted by its proxy. Life would still be fine if there where only one proxy, however several proxies do emerge to compete. Competition thus breeds differentiation.
How then can an implementation differentiate itself when there are based on a standard? The obvious way is to deviate from the standard, that is to ”extend” the standard. So, for the case of implementing a consumer of a protocol you can do two things. First, you could extend the original protocol to implement your new feature and second, you could make your consumer more tolerant to various producers. What eventually happens is that the best, and therefore the de-facto implementations are the ones that are the most liberal consumers. Producers now conform to de-facto implementations rather than the original specification. They conform to the best implementations which are the most liberal ones. Sloppy producers now become the norm.
So in the end, the absence of a standard implementation of a compliance test leads to competition and eventually the emergence of de-facto standard implementations that are extremely liberal. The vicious cycle continues with producers that deviate from the original spec. The moral of the story is, before releasing a specification, make sure you have a solid compliance suite, otherwise expect the specification to be subverted.