February 14, 2018

Writing Open Source That People Will Use

This post is geared toward Elixir, but the principles apply just about anywhere.

Writing Open Source That People Will Use

You solved a problem. You made a package. Cool right? But why is it not gaining the traction it should?

A useful package can have terrible execution if not carefully planned. As the author of Pigeon, Kadabra, and Scribe, I've taken quite a bit of time to study and design open source that not only works well, but is a pleasure to use. It's been a difficult process, but very rewarding.

Want to build better Elixir modules and open source packages? These are some of my principles.

The 30-Second Rule

A developer using your module/package should be able to do something with it within thirty seconds of opening the README.

There are definitely exceptions to this rule, but the vast majority of packages you encounter should not be inherently complex. Timex is a wonderful example of a great quickstart guide. Despite being a very heavy package with lots of functionality, the README can get you up and running with many of the common use cases for Timex.

Hidden Customizability with Sane Defaults

Having a great quickstart guide does not mean stripping customizability from your API. It merely changes where you document it.

Making configuration options first-class in the README is probably the single greatest reason someone might avoid using your package. Instead, hide them in moduledocs and typespecs.

For example, this is Pigeon's quickstart configuration for an APNS worker:

config :pigeon, :apns,
  apns_default: %{
    cert: "cert.pem",
    key: "key_unencrypted.pem",
    mode: :dev
  }

This is the bare minimum to get a worker up. Are :cert, :key, and :mode the only options available? Of course not! There's 7 keys in total, but only those three are required. The other options are set to reasonable defaults and will largely go unnoticed by most users of Pigeon.

An important takeaway is that users often don't care about most of the internals. They will only look something up when they need it (unless they like reading documentation for fun). Don't try to impress a potential user by featuring all of the customizability in the README.

Make Your API Easy

The best API is one that a user can predict without having to look it up. How do you do this? Make your functions easy to remember! This will vary by language, but as a rule of thumb in Elixir, I try to keep my functions to one or two parameters with an optional third opts keyword list.

# Do this
def login(%User{}, opts \\ [])
def login(email, token, opts \\ [])

# Not this
def login(email, username, token, is_admin?, expiration_timestamp)

Sometimes a function really will need 5 parameters, so what do you do? Encapsulate a lot of related data in structs. This is basic refactoring, but it's amazing how easy it is to miss. Don't make your users think and they'll be much happier for it.

Don't Be Lazy

Ultimately the success of your package depends on the effort you put in. Code is a reflection of yourself as a programmer, regardless of whether or not someone paid you to write it.

I spend easily 60% of my time working through the API and usability of package, even more than the time required to write the code. That's what it takes to write something great.

Interested in seeing the open source Codedge has built? Check out our Github!