Six Thoughts Before We Start 9
Thoughts on Postel’s Law
Jon Postel wrote an early specification for the Transmission Control Protocol (TCP), one of the core protocols
of the Internet protocol suite. You use it every day to surf the web, send emails, etc. One of the guiding
principles that he used when writing it was this:
Be conservative in what you do, be liberal in what you accept from others.
This idea is also called the “Robustness Principle”, and is sometimes rephrased as “Be conservative in what
you send; be liberal in what you accept.” When applied to TCP, it means that the sender of data should be
strict in what is sent, ensuring that it is accurate and precise. It also means that the receiver of data should be
forgiving and understanding of data to as large a degree as possible. If you send data, be as clear as possible
in what you send. If you can accept sent data, then you should.
Any application programming interface (API) should follow this principle. The same principle should apply
to your code. The public interface of your class should be viewed as an API. It should be conservative in what
it sends and forgiving in what it receives. When calling another API, your code should send out correctly
formatted data, following the rules laid down by the API. It should, however, be willing to receive incorrectly
formatted input as long as that input can be understood.
You shouldn’t be so liberal in accepting input that you allow things like SQL injection and buffer
overflow exploits. Take care to protect yourself while you are being forgiving in what you accept.
For instance, if passed a string, you might be happy to accept strings with blank spaces on the beginning and
end, and use the Trim function to clean things up for the sender. Consider the situation where the input is a
name. Clearly, a name should not have spaces at the beginning or end. However, you should accept a string
that has such spaces. Why would you reject it? You wouldn’t. Nor would you leave it in the form it was sent
to you before accepting it.
Another example? Paths. Say you have a function that accepts a path as a parameter. Say,
procedure WriteFileToDisk(const aPath: string; const aFilename: string);
This procedure should be able to deal with a path that either has or does not have the proper trailing delimiter.
You should gladly accept both. Of course, it is up to your internal workings to fix things up properly, but your
code should be forgiving and take both “c:\mypath” and “c:\mypath” with equal grace.
Your classes might provide overloads for input methods, accepting both an integer and a string as input,
providing a way for your class to be as forgiving as possible. It may be that your class has an ID property of
type integer, but the caller of your application holds that ID as a string value. You should, of course, accept
the string value as long as you can convert it into a valid value for your application.
On the other hand, when you call another API, your code should be strict and always send data in the correct,
expected form. You should trim your string names before they get sent along to the API you are calling. If the
system expects integers, you are going to send integers meeting the specification completely.