Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save softinio/2fde25dd5a4a6e13c02acadf961e2bbf to your computer and use it in GitHub Desktop.
Save softinio/2fde25dd5a4a6e13c02acadf961e2bbf to your computer and use it in GitHub Desktop.
Notes for livestream on contributing to open source projects

These are my rough notes when preparing for a Haskell livestream that I thought would be worth sharing. Some things are general comments on contributing to the open source ecosystem whereas other notes are specific to the stream (e.g. Haskell and the streamly package)

How things look from a maintainer's point of view (for highly active projects):

  • Reactive

    As projects become more active the maintainer's "inbox" gets pretty large. A significant part of their routine is triaging their inbox.

    In this situation, maintainers commonly forget about the "big picture" of the project, including major deficiencies in user experience, due to this reactive workflow. Usually once a maintainer gets through their inbox their willpower is drained, so they don't take initiative to make any further improvements beyond what users requested.

  • Oversubscribed

    Most project authors bite off more than they can chew, and they eventually have to start deciding which requests to skip (either explicitly or by ghosting the request).

  • Bottlenecks

    If maintainers don't document/automate workflows or process then they have to put work into shepherding outside contributions and the maintainer becomes a bottleneck to outside contributors. If the situation is really bad the maintainer puts more work into shepherding outside contributions than it would have taken to do things themselves, which is an unfortunate situation for everybody involved.

Given that, how can you help contribute to another person's repository:

  • Start by contributing small changes to "test the waters"

    This helps guage how open the maintainers are to outside contributions. (In my opinion) Good maintainers will entrust you with authority early on.

    Great example: Haskell's lens library (Edward Kmett freely shares commit bit for all of his projects)

    Opposite example: Nix (authority is rarely delegated, as far as I can tell)

  • Help improve the contribution or release process

    Study historical pull requests or releases and see if there is something that can be automated. For example, volunteer to contribute or improve CI pipelines or document processes (e.g. .github/CONTRIBUTING.md). Anything that makes it easier for new contributors will relieve the maintainer's burden and increase the leverage of outside contributions.

    Sometimes this can be as simple as writing down "How do I get permission to X" where X is:

    • "get the commit bit"
    • "get maintainer privilege on some community infrastructure"
    • "cut new releases"
    • "tweet or blog about the project in an official capacity"

    Also, "DevOps" experience is in high demand in the open source ecosystem and can make a huge impact on project adoption. For example, projects that release pre-built binaries for multiple platforms have a significant competitive edge over projects that require building from source.

  • Use the package and fix what you find

    As a new user of the package, you see it with fresh eyes and all the warts of the user experience are clear. Fix those warts!

    As a new contributor you have a large advantage over the maintainer that you might not yet appreciate: you have plenty of time to carefully think through and improve the holistic user experience. You're not distracted by the process of triaging incoming issues, so take advantage of that space and creative freedom.

Example project we'll use for livestream: streamly, a stream processing package for Haskell

I picked this package because it's already in very good shape and illustrates a lot of good open source practices

There are two experiences we could potentially improve:

  • The experience of new users
  • The experience of new contributors

We'll focus on improving the experience for new users

Let's think through the entire "experience" of how a user might use streamly

  • Motivation

    How does a user even know that they even need a streaming library in the first place?

    For example, a lot of Haskell users will just write an explicit recursive loop without a second thought that they even should be using a streaming library.

    Or maybe they don't need a streaming library! How do they know what is the threshold for using a streaming library? This is a very common question that novice Haskell users struggle with.

    Some ways to improve this are:

    • Answering Stack Overflow questions where a streaming solution is an appropriate solution (i.e. not overkill)

    • Writing blog posts about the package to raise awareness that this class of problems and solutions exist

  • Discoverability

    How do people find out about your package specifically?

    • Adding the package to various catalogs of recommended solutions

    • Word of mouth

    • Search keywords (e.g. Hackage categories, search engine optimization)

    • Project website

  • Evaluation

    How do people select your package against competing solutions?

    • Comparative evaluations with other packages (e.g. benchmarks)

    • Ranking systems (e.g. Hackage votes, slant.co)

    • Skimming documentation/tutorials/blog-posts

    • Activity and/or reputation of authors / maintainers

    • Overall perception of quality

    • Word of mouth

  • Simple self-contained example

    • Probably the most common step that projects forget to do

    • Is there an example program?

    • Where is the example program? In the README? In the generated documentation? In an ./examples directory on GitHub?

  • How to build the example

    • Yes, you may have to teach users to use their compiler or build tools even though it's technically not your project's responsibility

      Most novice users are struggling with their build tools, across all programming languages, and most of your users are novice users

  • How to integrate your package into an existing project

    • cabal vs stack vs Nix instructions

    • Again, technically not your job, but helps to spell it out anyway

    • Poor example: reflex, since you have to integrate with their project instead of the other way around

  • How reliably does your package build?

    • Is your package on Stackage?

      Easily the most important thing you can do to reduce build failures for your users

      This also gives you Nix support for free. Nix ecosystem closely tracks Stackage

    • Are your dependency bounds correct?

      Upper bounds are more work to maintain, but bounds failures are a better end-user experience than build failures and easy to amend via Hackage revisions.

    • Does your package have non-Haskell (e.g. C) dependencies?

      You can declare these as required dependencies in your .cabal file

      Some common dependencies that people can be unexpectedly missing from user systems:

      • zlib
      • iconv
      • ncurses
  • Documentation coverage

    • 100% haddocks?

    • Doctests?

    • @since annotations?

    • For each type, it's often useful to document these three things:

      • How to create that type
      • How to transform/combine that type
      • How to consume that type
  • API

    • Are the right things public / private?

    • Are the module names well-chosen? (e.g. Control.Monad.Trans.State vs Streamly)

    • Should internal modules be made available?

  • Okay, now to get to the actual code 😅

    Most things that are code-specific will be covered in the issue tracker

    Just browse open issues and take a crack at fixing them

    There are still some generic improvements to the code you can make, too

  • Error messages

    Levels of error messages:

    • No error (silently transform a failure into a fake success)
    • One-liner (Exception: Prelude.head: empty list)
    • Expected: … / Actual: …
    • Here's what went wrong: …
    • Here's what you should do: …
    • I automated away what you should do
    • The invalid state is no longer representable (i.e. now a type error)
  • Type-level experience?

    • Are inferred types good?

    • Are type errors good?

    • You can add custom type errors in Haskell! This is a light-weight and high-value contribution!

  • How do users get help?

    • Issue tracker (e.g. GitHub)
    • Stack Overflow
    • Discourse
    • Gitter
    • Discord?
    • Twitter?

    Is it an easy and enjoyable process for them?

    Is the support process or forum discoverable?

    Are users left hanging or ghosted by maintainers?

    Do they know what is expected from them when they file bug reports?

    Is it clear if the ball is in their court or in maintainer's court for any given issue?

  • For frameworks (e.g. Yesod, Cloud Haskell, or Reflex): how to deploy the application to production

    Again, not your job, but your users expect somebody to hold their hand and tell them how to do this and that somebody is probably you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment