Awesome FOSS Logo
Discover awesome open source software
Launched 🚀🧑‍🚀

Building an interface (even if there's only one implementation) is unquestionably right


tl;dr - Large components of systems you build deserve an interface, even if there is only ever one implementation. If you want your code to be good, put a bird interface on it!

I’ve gone back and forth, but for the last maybe 5 years my opinion has hardened. My stance is now that it is unquestionably right to always build an interface for large components of a given system, even if you only have one implementation early on.

Why though?

Here’s why:

  • Someone else can come along and add support for their pet favorite $EXTERNAL_IMPLEMENTATION
  • Interface maintenance forces thought about what is generalizable and what isn’t
  • Even if you never build a second implementation, it’s much easier to understand the structure of a component from an interface
  • Interfaces are contracts, and interoperation is about contracts (whether inside your program or outside)

Projects I wish did this

I’ve seen this play out numerous places – here are a few which are top of mind:

  • Kubernetes should have built in optionality for ETCD, is just is not necessary for 90% of HA deployments
    • Being able to just point a control plane @ a managed DB provider (ex. RDS) would have been infinitely better
    • I’d argue more people know how to run Postgres in HA setups than ETCD.
    • Kine exists now (thank you very much to the creators/maintainers), but it shouldn’t have been necessary to begin with
  • Graylog only supports MongoDB for metadata storage (but they did just release support for OpenSearch in 4.3.0)
    • If all you’re doing is storing/manipulating JSON documents, put it behind an interface!
  • Ghost only runs on MySQL 8.0
    • Postgres was supported briefly but they removed support – if Ghost had started early with a good interface, it would be much easier to plugin-ize support (and they wouldn’t have to maintain it)

I’m not saying you have to go all the way and build in a runtime-loadable plugin system! But please at the very least build in some leverage so that people can safely do some new construction on bits of your majestic software house.

What I see often is that people will use a database library that has support – note that this is not what I mean. Often this makes a project worse, because they have to stick to writing subsets of SQL that are cross-DB. It’s much better to have a DataBackend that has implementations like Postgres14DataBackend and MySQL8DataBackend rather than just changing the driver: 'postgres' to driver: 'mysql' in some configuration file.

That said, I’m thankful for whenever projects at least have the SQL driver thing going – cross-platform SQL is often good enough.

Bonus hot take: Postgres is strictly better than MySQL

Disclaimer: I’m clearly greatly biased in favor of Postgres, as evidenced by this hot take and previous posts.

MySQL is truly great software (most of the modern internet is built on the LAMP stack, it has great features and stability), it’s more that Postgres is amazing.

The things Postgres does and can do, the way people build on it, the way it’s been governed, improved and continues on are exemplary – that’s why I’m always eager to see it in more places.

Also, as long as I’m doing random hot takes no one asked for, Ghost’s decision to remove Postgres support was the biggest mistake they’ve ever made (the software, organization and people that makes Ghost is amazing though – it’s an insane value and they legitimately make the world better).

In the recent release notes for Ghost 5, the team doubled down on MySQL 8.0 – likely a great thing for their productivity, though a bunch of SQLite users will be sad. The real pain for me was finding out about their decision from so long ago to drop Postgres support. I do appreciate their generosity and transparency in sharing their reasoning – Ghost is run is a breath of fresh air, and the amount of value they deliver for free (and with paid plans) is insane.

They’re not completely against re-adding it, but the chances of that are slim to none – an interface around the one implementation could have helped others (who cared enough) maintain a separate plugin though. I mean even if you weren’t a Postgres fanatic, it might be cool to try running ghost on something more exotic, like Object storage or Git!

It’s a spicy meatball take (also something a junior engineer/sith might say), but Postgres is strictly better than MySQL, full stop.

MySQL 5, MySQL 8, doesn’t matter, doing lots of concurrent transactions or not, I want Postgres 100% of the time that I see MySQL, and it puts me off using entire projects.


In short – if you want your code to be cool, put a bird interface on it!