For about four years now I’ve maintained the open source Apache Kafka C/C++ client library - librdkafka, this blog post outlines what I’ve learned from its little open source odyssey, covering everything from bit-level compatibility to interpreting engrish.

Countless (if you are really bad at counting, like me) applications have been written using librdkafka, and the community has written language bindings for almost all of the prevalent programming languages on top of it, such as the two I wrote for Confluent: confluent-kafka-python and confluent-kafka-go. See this somewhat complete list for more.

Let’s get down to business.

Open source community

Open source is great, and all that, and unrelentless. I’ve spent on average 1–2h per day the last three years providing free support to the online open source community. Most of it is answering questions, explaining concepts, pointing out that it is already in the official documentation. Then there’s the inevitable and countless troubleshooting and guidance of users who’s assumptions are not in line with the application <-> library contract. And last, least, and most important: issues of varying quality filed for actual bugs in the library.

There isn’t much of an alternative, this is how open source works.

If I could give users seeking help a few tips, it would be:

But, this is probably the wrong medium (he he) for users.

So here are some guidelines for you as an open source library maintainer instead:

Use-cases — or, what you don’t know

You probably had a use-case when you decided to create your project and it will most likely have affected the design and interfaces of the project accordingly.

But you’re not only making this software for yourself, you also want everyone else to use it. Adaptation is the goal of open source projects after all.

If there is one thing I can tell you about user’s use-cases is that you don’t have any idea what they are, sure — they might surface every now and then in issues and emails but you are only seeing the tip of an iceberg.

With this in mind it is imperative that you try your absolute best not to constrain the use of your software:

API and ABI guarantees

Any C library worth its name must guarantee both API and ABI stability. SONAME bumps are frowned upon and must be avoided as far as possible since it’ll likely break existing applications.

API stability means that recompiling an existing program with a new version of the library will succeed and the program’s interaction with the library remains unchanged.

ABI stability means the same thing without recompiling the program. While API stability allows for changing public types, etc, ABI stability does not — the library must be completely binary compatible, on the bit-level, in all its public interfaces, to the previous version.

Configuration

Design your configuration properties so they reflect desired behaviour, not how to get there. Let them be the contract for which

Portability

Portability takes the fun out of programming.

Portability effectively means that:

Releases

For optimal reach, announce releases tuesday mornings (EST).

Treat yourself to a beer.

It is hard to maintain multiple releases for small teams, so try to avoid multiple release branches with backporting fixes, the increased test matrix and maintenance cost won’t pay off.

Some truths

WIP

This post is a work in progress, more notes will be added over time (unless this is really all there is to open source projects, then I’m done).