Friday the 13th. I just had to add slaughtering in the title…
What is an antipattern?
Antipatterns — such as those presented in Brown et al. (1998) — have been proposed to embody poor design choices. These antipatterns stem from experienced software developers’ expertise and are conjectured in the literature to negatively impact systems by making classes more change-prone and–or fault-prone. They are opposite to design patterns (Gamma et al.1994), i.e., they identify “poor” solutions to recurring design problems, for example Brown’s 40 antipatterns describe the most common pitfalls in the software industry (Brown et al). They are generally introduced by developers not having sufficient knowledge and/or experience insolving a particular problem or having misapplied some design patterns.
In this post the approach is more like the antipatterns of developer experience (in REST API world).
In REST world…
If you read blogs you’ll find a lists like this one:
- Tunneling everything through GET/POST
- Ignoring response codes
- Ignoring caching
- Ignoring hypermedia
- Ignoring MIME types
I could have read more and more blogs and articles, but I was lazy and wanted to engage developers again. Besides discussing with people (even via a social media tool) is more fun than with blogs or articles. Try to discuss with an article and you see the point. I wanted to have a fresh approach and see if my Twitter bubble/crowd AI would bring up some not so commonly mentioned antipatterns. I did get response from the bubble :)
The thread resulted to having a lot of responses and debate. Which is good! That was the purpose. After the fire burned out I started to think the topic again. This post could have been set to be “80% is enough”.
I came to the conclusion after having a short debate with Michael Hibay. He was argumenting to take a different stand on the matter and suggested the positive approach. He injected in the discussion a link to a great post of “Guidelines for Designing Hypermedia Web API”. That is a good suggestion. Although approaching the thing from “how things should be done” results to different learning result and experience than calling out the things to avoid. Some principles listed in one place does not equal that everything against the principles is antipattern. To argument otherwise would suggest that the original list is perfect.
My arguments to Michael was that practicality wins the puritanity. Even if people want to create perfect REST or RESTful APIs, that hardly ever is possible in other environments than academia. We are limited by time, availability of right people, knowledge, energy to do the right thing. In most cases you accept that your solution breaks the holy principles of http or what Roy Fielding wrote in his famous dissertation. Your goal is to get the product in the markets or solve client’s problem. In those cases you of course try to avoid waste and even try to look ahead as much as possible.
But you accept that 100% solution is not feasible and settle with the 80% solution.
Shit might hit the fan sooner or later and that risk is accepted in 80% solution.
Another thing is what is already a common practise. Fighting against what has become widely adopted practise is not a viable option for all. Right or wrong, for example the versioning is commonly expressed in the URL. If looked at from http and RESTful angle, that is wrong. You should not do that. Yet that is a practise more or less. Now the customers of the APIs are accustomed to it. They often even expect it. Going against the mainstream is just Don Guijote act against the odds. Don’t get me wrong, wise people have given a lot thought to http and REST, but we don’t live in a perfect world and sometimes it’s just better to accept imperfection than fight it. Pick your battles wisely.
Now back to the rest of the antipatterns in the discussion. Here’s a few picks from the thread. You should read it all from Twitter: thread one, and thread two.
API or call is not idempotent for whatever reason
From a RESTful service standpoint, for an operation (or service call) to be idempotent, clients can make that same call repeatedly while producing the same result. In other words, making multiple identical requests has the same effect as making a single request. Note that while idempotent operations produce the same result on the server (no side effects), the response itself may not be the same (e.g. a resource’s state may change between requests).
The PUT and DELETE methods are defined to be idempotent. However, there is a caveat on DELETE. The problem with DELETE, which if successful would normally return a 200 (OK) or 204 (No Content), will often return a 404 (Not Found) on subsequent calls, unless the service is configured to “mark” resources for deletion without actually deleting them. However, when the service actually deletes the resource, the next call will not find the resource to delete it and return a 404. However, the state on the server is the same after each DELETE call, but the response is different.
GET, HEAD, OPTIONS and TRACE methods are defined as safe, meaning they are only intended for retrieving data. This makes them idempotent as well since multiple, identical requests will behave the same.
Antipatterns kill developer experience
That is typical Viljami again. He steels the show by listing a lot of items. That reply alone was different to the example given above of the typical blog post contents under the title “REST Antipatterns”.
Incorrect HTTP verbs and bad response codes are result of neglecting the principles of http. A lot of the antipatterns listed by Viljami actually make the API harder to adopt and use. Those antipatterns have clear negative usability effect eg the developer experience sucks.
Going for non standard authentication practice is also DX killer since there’s already valid solutions with long track record available. The tooling for de facto standard solution are available, a lot of the devlopers are familiar with those and just can proceed faster with those.
Missing pagination should be obvious. Consider a collection with 50 000 or 500 000 items. Do you really want to list all of them with one API call? Is that your normal case? Or would you prefer to have opportunity to split the collection into chunks and get what is needed in the app? You probably don’t want to list those 500 000 items in one view for example. That is not good for network resources point of view either.
When asked what are examples of incorrect HTTP verbs, Viljami responded very much what I expected: “Using POST to update or replace resources is a common one. DELETE with a payload is another one. Sometimes you even see exotic stuff used like GET with actual payloads or strange implementations for HEAD.”
No one likes chatty APIs. Those make you do several API calls to get what you need. Often that is due to bad API design or lack of information how the API is used eg use cases.
Second set of antipatterns
Also Michael posted a couple of lists of antipatterns. Here’s one:
I can see that exposing your database via REST is not a good practice. Often in those cases the the knowledge of the context is hidden and field names are exposed as is. That is hardly usable to larger audience of consumers let alone can be a security risk.
Caching obviously is another thing easy to grasp. Making it hidden results to bad experience with API and also in the app which uses the data or functions of the API.
Not using HATEOAS is something we can debate. If done right and otherwise the design of the API is really good, using HATEOAS results to good experience. In reality often the result is the opposite. Result is too often above mentioned chatty API.
Mixing JSON and XML
This was raised again by Viljami. I get the feeling that Viljami is trying to steel my blog series just by providing a lof of practical material. This is pretty weird looking antipattern, but I can see the reasoning behind it. But don’t do this :) Pick one and stick with it.
I did not have the energy to go through all the things since it’s Friday and I had a long day.
Some more to read from 100 Days DX
- #85 - Great Developer eXperience requires fluent internal workflow
- #84 - Theory of Economics of Developer eXperience
- #83 - The Space of API Design Decisions is missing
- #82 - Purpose of API Evaluation Framework
- #81 - Should We Move to Stack Overflow?
- #80 - Four data driven ideas for improving API documentation
While you are here...
Check out Platform of Trust in which I've worked to enable best possible developer experience!