6.3 Interfaces as Black Boxes

On a similar note to that of the last section, we should treat our own components no differently than how we treat third-party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third-party code — if that’s at all possible, in some cases. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.

One way to improve our interfaces is to write detailed documentation about the input an interface touchpoint expects, and how it affects the output it provides in each case. The process of writing documentation leads to uncovering limitations in how the interface is designed, and we might decide to change it as a result. Consumers love good documentation because it means less fumbling about with the implementation (or its implementors), to understand how the interface is meant to be consumed, and whether it can accomplish what they need.

Avoiding distinctions helps us write unit tests where we mock dependencies that aren’t under test, regardless of whether they were developed in-house or by a third-party. When writing tests we always assume that third-party modules are generally well-tested enough that it’s not our responsibility to include them in our test cases. The same thinking should apply to first party modules that just happen to be dependencies of the module we’re currently writing tests for.

This same reasoning can be applied to security concerns such as input sanitization. Regardless of what kind of application we’re developing, we can’t trust user input unless it’s sanitized. Malicious actors could be angling to take over our servers, our customers' data, or otherwise inject content onto our web pages. These users might be customers or even employees, so we shouldn’t treat them differently depending on that, when it comes to input sanitization.

Putting ourselves in the shoes of the consumer is the best tool to guard us against half-baked interfaces. When — as a thought exercise — you stop and think about how you’d want to consume an interface, and the different ways in which you might need to consume it, you end up with a much better interface as a result. This is not to say we want to enable consumers to be able to do just about everything, but we want to make affordances where consuming an interface becomes as straightforward as possible and doesn’t feel like a chore. If consumers are all but required to include long blocks of business logic right after they consume an interface, we need to stop ourselves and ask: would that business logic belong behind the interface rather than at its doorstep?