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
vsstack
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
fileSome 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
vsStreamly
) -
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
- https://github.com/composewell/streamly/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
- composewell/streamly#11
- composewell/streamly#293
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