The Robustness Principal and internal APIs


RFC 761 section 1.2.2.

2.10. Robustness Principle TCP implementations should follow a general principle of robustness: be conservative in what you do, be liberal in what you accept from others.

RFC 1122 elaborates with section 1.2.2.:

1.2.2 Robustness Principle At every layer of the protocols, there is a general rule whose application can lead to enormous benefits in robustness and interoperability [IP:1]: “Be liberal in what you accept, and conservative in what you send” Software should be written to deal with every conceivable error, no matter how unlikely; sooner or later a packet will come in with that particular combination of errors and attributes, and unless the software is prepared, chaos can ensue.

For anything expected to interoperate “in the wild” with other implementations of a given standard or API this approach is optimal as both competitive advantage and user experience. A browser that accepted only valid HTML would not have been successful in a world with Netscape 1.0.

For internal APIs, however, it is better for implementations to reject invalid or malformed requests with informative error messages rather than muddling along.

Within an organization integration testing should catch errors before they affect user experience. Failing quickly reduces the chances of future revisions of software needing to be “bug compatible"with easily avoided problems. It’s not a competitive advantage to muddle along with bad input in internal systems where there are no competitors to “out-compatible”.

For example, if a company has standardized on UTF-8 as a wire format for text it is probably best if all new implementations of services validate that their input is correct UTF-8 at every edge and refuse to process anything that is invalid. Otherwise eventually some system is going to end up having to try and guess the correct encoding in order to proceed and serve valid data that came in an API that didn’t validate and has to go out an API that must be valid. When a system has to accept input from the Internet (from users or as an input) then all of the “muddling along” can be in the ingestion layer.

This only applies, of course, when both sides of an integration are new enough to be tested together but this applies to a lot of new development within an organization – a new capability is being added to an entire “stack” resulting in API revisions at each layer. It’s better to catch problems at the first opportunity rather than ending up years later with tons of special compatibility hacks where an API is versioned based on the different clients foibles rather than by design.

Internal APIs should be designed to be easy to use correctly – but once designed they should only work when used correctly.