API design and granfalloons
Posted on July 9, 2009 by Tommy McGuireI was just re-reading the quote from Steve Vinoski,
Developers who favor technologies that promote interface specialization typically raise two specific objections to the REST uniform-interface constraint. One is that different resources should each have specific interfaces and methods that more accurately reflect their precise functionality.while I just finished reading chapter 12 of RESTful Web Services on frameworks, particularly the section on Restlet.
In that chapter, Jerome Louvel and Dave Pawson write,
The central concept of Restlet is the abstract Uniform class, and its concrete subclass Restlet....The main method is handle, which takes two arguments: Request and Response....Every protocol that Restlet supports is exposed through the handle method. This means HTTP (server and client), HTTPS, and SMTP, as well as JDBC, the file system, and even class loaders all go through handle. This reduces the number of APIs the developer must learn.I have not used Restlet; it looks very nice and in this instance, its approach may be perfect. Further, the examples I have seen show no signs of the problem I am about to describe. This blogage is in no way a criticism of Restlet. Just that last quote, particularly the last sentence.
The thing is, that quote brings two things to mind: the Lego fallacy, and ioctl. More about the former later.
ioctl is a system call introduced, according to FreeBSD man pages, in "AT&T v7"; presumably seventh-edition Unix. It is an addition to the basic open/close/read/write system calls used to "manipulate the underlying device parameters", or more generally to provide a "miscellaneous" interface. ioctl in general takes as arguments a file descriptor, an integral request identifier, and stuff that depends on the request. (It is perhaps the best abuse of C varargs ever written.) Currently in Linux, there are ioctl requests to shuffle around on a tape drive, and shuffle tapes in a tape library, fiddle with the terminal, with the sound card, and with a cdrom drive. In general, ioctl is a bit of a crawling horror.
Now, as I wrote above, I do not know if Restlet is affected by that particular doIt semantics. I have, however, worked with code that exposed all of its protocols through a single method name to reduce the number of APIs a developer needed to know, and that particular solution to API complexity was roughly akin to hiding the body under the throw rug: not only was it still obvious, but I was also constantly tripping over it. Think of 20 or so classes each mostly made up of a read method.
Ultimately, the problem is the Lego fallacy. How do I get "Lego fallacy" out of one of the most influential networking research projects of all time? Simple:
Horus protocols are structured like stacks of Lego-blocks, hence new protocols can be developed by adding new layers or by recombining existing ones.Once upon a time, a faculty member whose name I cannot recall visited UTCS and gave a talk on Horus and Isis. The particular example he gave of the Lego blocks were labeled "encryption" and "compression". If that last sentence did not leave you boggling, consider: Those two operations cannot be arbitrarily composed; I do not know, but I would bet pretty much anything that encryption could be mathematically defined as the process of making something incompressible. Once a block of data is encrypted, it is effectively random bits, and random blocks of bits cannot be compressed because there is no redundancy to exploit. Hence the Lego fallacy: sometimes the interfaces can look alike, like data in/data out, but that does not mean the operations can be used alike. Sometimes the semantics are wildly different, and it would be much better if the interface exposed those differences.
What does this have to do with REST? Not much. Both REST and WS* can accuse the other of exposing all of their operations through a single interface, regardless of semantics. Both accusations would be roughly false: REST has a few operations, but they are exposed with different semantics on a large number of URLs; WS* POSTs everything to a single URL, but that is an implementation detail, the import part of the API is the method stubs.
What does it have to do with Restlet? Probably nothing. The other hand here is something like a data-flow system, with a large number of clearly labeled operational blocks that can be composed to build a system. Certainly, this is no worse than a dynamically typed (excuse me, untyped) programming language, where it is up to the programmer to ensure the combined operations make sense and that the resulting program is clear to a reader.
I suppose ultimately my point is that reducing the number of APIs at the cost of increasing the complexity of those APIs is not necessarily a win, that similar things can look similar, but different things really ought to look different. Sometimes interface specialization is good even though other times it is akin to a granfalloon.