On 'Explicit is better than Implicit'

Since a few people haven’t listened to the podcast I thought I would try to explain some of the main points. I’m not sure I can enumerate everything here with as much nuance as we had on the show so I’d still recommend listening. But hopefully I can capture the main points.

I made the case on the show that a lot of the apis that people like in elixir tend to be highly implicit apis. I also made the case that explicit apis tend to be worse apis then implicit apis. That was my contrarian opinion. So now I’ll try to justify it.

When I’m talking about implicit apis what I’m really talking about is encapsulation. A key part of good api design is about hiding large amounts of complexity behind a small interface. If this is done well then the end user doesn’t ever notice the underlying complexity which is really as good as removing complexity altogether. The interface should be small for similar reasons. If you need to chain together multiple api calls in order to use a module then this is a more complicated api then an api that accomplishes the same goal through a single api call. A good example of this would be if every time you wanted to execute a query through ecto you also needed to check out the database connection yourself, parse and compile the query yourself, send the query to Postgres yourself, etc. I refer to APIs like this as “maximally explicit APIs”. They tend to be cumbersome to use and more error prone. But ftmp ecto hides all of this complexity and it’s a better api because of that.

But all of those details are “implicit” to us, the end users of Ecto. We don’t see how any of that stuff is managed from an api perspective. Sure there are escape hatches into that level of the system. But generally you don’t have to wander down there. At our layer of the stack the call to Repo is explicit, the query is explicit, and everything else is encapsulated.

Obviously those details are handled somewhere. If you work on a database pooling solution then you might have to care about them. But at our layer we’re able to ignore them and instead be more explicit about our domain logic.

The trend I see is that people have taken advice like “explicit is greater than implicit” and are carrying it a little too far. If you build a “maximally explicit” api then you quickly start to limit your ability to encapsulate complexity. If you take explicitness to it’s limit then encapsulation becomes impossible.

I think when people say they want explicit APIs over implicit APIs what they really are saying is “don’t surprise me”. If you say to ecto “run this query” you expect it to run the query. You don’t expect it to run the query and also buy you a toaster. The rails example you mention @PragTob is a great example of a surprising api. It’s almost like it was designed to create surprise through indirection.

I think what we ought to be heading for are APIs that encapsulate large amounts of complexity - which means APIs that hide implicit details - and have few if any surprises. It’s a tricky balance. But I think that’s the correct strategy.

9 Likes