Yesterday you may have seen the @CaplinTech tweet about Zed Shaw’s essay which complains that programmers too often muddle the concepts of indirection and abstraction. In particular he bemoans that this confusion often results in programmers designing bad APIs.
While the distinction he draws is a valuable one, there is more of a relationship between abstraction and indirection than Shaw acknowledges; any indirection that allows for more than one significantly different implementation is in fact an abstraction of the common elements of those different implementations.
At Caplin, we feel passionately about the quality of our APIs and are dedicated to making them as good as possible. I believe that much more than any conceptual muddle between indirection and abstraction, poor APIs arise most often from poor design practices. When we are thinking about a user interface we invoke personas, tell user stories and involve UX designers. When we are thinking about a programmer interface it’s very easy to neglect these things (or their analogs) because the task can seem purely technical.
Nothing the customer sees is ever a purely technical concern. Many APIs are carefully designed and these tend to be sane abstractions in both the programming sense and the sense that Zed accepts. Where it’s easiest to forget to do the design work is where an API is created as part of a refactoring. When you already have some code and the programmer’s focus is on adding a layer of indirection so that the already existing code can be replaced, it is easy to allow the assumptions in that code to leak out or to allow the surface area of the indirection to be far too large in reflection of technical issues that the user doesn’t care about.
We must not forget that if we really expect the customer to replace a piece with custom code then some real person will have to understand the interface and write the custom code. They need to be able to do that without understanding the intricacies of the original code.
One way to mitigate this problem is simply to be aware of it and vigilant when a new API is arising. Don’t let it happen without conscious thought. If it’s something that a customer will see then it definitely needs more design work than you’ll put in within the course of a refactoring. I’ve also found it very helpful to involve people who aren’t as close to an API to help you document it, this can very quickly throw up bad design decisions.
Understanding the definitions of abstraction and indirection is valuable, but when it comes to API design the most important definition to think about is that of deliberateness.