This blog post is a cross post from a guide I wrote on the Commercial Haskell Github account. That URL is the authoritative location for this document. If you want to send any updates and recommendations, pull requests certainly welcome!
Maintaining an open source project is not trivial. It requires not only technical skill, but also social and time management skills. Finding the balance between helping others contribute versus implementing changes yourself, or between being helpful and being a slave to your project, is tricky. And worse yet: it’s non-obvious when starting an open source project that these problems even exist! The goal of this guide is to elucidate this topic, and clarify options.
This guide is obviously non-binding in any way: anyone is free to maintain their project in whatever way they wish. But hopefully this guide will make it easier to maintain a project. Finally, this guide is itself an open source project following the guidelines below. In particular:
Maintenance level: dedicated
Accepting maintainers: yes, request via PR
By making something open source, you are not giving any guarantees to users of the software of any kind. However, some people may expect certain levels of maintenance unless told otherwise. To avoid confusion and frustration on both the user and maintainer sides, it’s a good idea to define your maintenance level explicitly, in the project’s README. Here are some suggested “standard” levels you can reference:
Abandonware: this code is available as-is, but the author has no interest in it. If you find a use for it, great. But don’t expect PRs to be merged, or issues to be responded to.
Interested: the author has some interest in the project, and may merge PRs/respond to issues. However, don’t expect much.
Happy to merge: the author will review PRs and merge good ones, but is less likely to respond to issues
Dedicated: the author will strive to review PRs promptly, and get back to issues in a reasonable timeframe, usually within a week. Of course, real life has its own demands, and vacations happen, so the timeframe may be delayed.
Highly supported: there is a dedicated team of maintainers working to keep this project running smoothly. PRs will be reviewed and merged very quickly, and issues should be responded to within 48 hours, barring unforeseen circumstances.
In addition to these levels, it’s also good to specify whether people can request that they be added as maintainers as well. This could look like:
No: not interested in having other maintainers on the project
Yes, request via PR: if you send a few good PRs, and say you’re interested in being a maintainer, you’ll get commit access
Yes, request via issue or email: specify a contact method, and what the requirements are to get maintainer status
Again, these are just suggestions, and you can of course define your own level (or leave this alone entirely!).
You should make it as easy as possible to contribute to your project. And this means you should use standard approaches whenever possible, for two reasons:
People have already learnt these approaches. Even if your new approach is better, do not underestimate the resistance people will have to learning something new! This isn’t stubbornness on anyone’s part, it’s a natural defense mechanism against needing to learn thousands of variations on the same theme.
Standard approaches have been battle-tested to solve common problems people run into.
Here are some things you should consider:
Put useful information into a README.md file in the root of your repo. In addition to information on how to use your project, it should give some pointers on how to contribute, even just as a link to another document. Make sure to include:
A list of project goals, to hopefully clarify whether a certain feature fits in with the project or not.
The maintenance level, mentioned above.
Any information about how you like to receive PRs. This can be highly opinionated, and provided as a link. Here’s my highly opinionated guide: https://www.snoyman.com/blog/2017/06/how-to-send-me-a-pull-request
If you’re using Github or similar, provide issue and PR templates to help people file useful issues and complete PRs. As one point of reference, see Stack’s .github directory: https://github.com/commercialhaskell/stack/tree/master/.github
If you care about consistent styling, be sure to include a reference to the style guide.
Add CI scripts that enforce what you care about. It’s much easier for a contributor to fight with Travis or AppVeyor than to have a higher-latency back-and-forth with the maintainer. CI can be used for styling, linting, and much more!
This ties in directly to the maintenance level. What I’ll describe here is the ideal goal to strive for. But keep in mind what we discussed earlier: you’re not a slave to your open source projects, and have the right to say “I’m not going to deal with this now, or ever.” But please consider being upfront about such a decision!
Triage quickly. If new issues come in, have a standard triage process, which will include:
Labeling the issue
Asking for more information (ideally, have a standard issue template that requests the most common info already)
Telling the issue reporter that it’s being looked into
Define an owner, who is responsible for driving an issue forward. This is vitally important on multi-person projects. It’s too easy for issues to remain in limbo because no one knows who’s ultimately responsible for making a decision.
Define clear steps to closing the issue. It can be frustrating for everyone involved if there is no way to move forward. Get a reproducing test case, say “if this passes, we’ll close the issue,” etc.
If issue filer unresponsive, close it. There is limited time in everyone’s life, and limited energy in the universe. Unnecessary open issues clog up people’s mental capacity. If you don’t hear after X amount of time, close with a comment “closing due to unresponsiveness.” Ideally, explain this in the README or contributor guide; it’s not a personal slight, it’s just official policy.
You will receive feature requests and pull requests which don’t fit the project’s goals. You’ll receive poorly written PRs. It helps no one involved to drag out the process if you know this will never be worked on. Say no upfront, ideally explaining why. If there’s a possibility to fix the request/PR, leave it open. If it’s inherently mismatched, close it out. (But please don’t mute the conversation, that’s rude.)
Related to this: encourage contributors to open up issues before submitting large PRs. A large PR adding a feature that won’t be accepted is frustrating for everyone involved: contributors wasted their time, and maintainers hate turning away work. Better to have a design phase. (I mention this in my opinionated PR guide.)
Be sure to label issues that you think a newcomer will be able to work on. It provides a gradual onramp to understanding the code base, and getting PRs merged is a dopamine hit for everyone involved. Resist the urge to knock out the easy issues yourself! You will spend more time helping a new person with an easy issue than doing it yourself, but it’s an investment in their future, as well as your project’s.
Opinionated recommendation: be free with the commit bit once people prove themselves, they rarely abuse it, and you can always revert something bad. I typically give out a commit bit (if I remember to) after 2-3 successful PRs. (I think this was originally advocated by Edward Kmett.)
Whether explicitly in your README, or implicitly with how you communicate, you should try to motivate people towards wanting to contribute. There is little glory in day-to-day maintenance of an open source project. You should give people getting involved as much in the way of positive reinforcement as you can. Ideas include:
They will be able to hone technical skills
They will get access to mentorship from someone with more experience (see below)
They will be empowered to fix problems that are hurting their work, instead of being blocked on an upstream maintainer
It can work as resume building. Note that, unfortunately, some employers are not incredibly interested in FLOSS experience. But many others do weigh such activities heavily.
When you have the time and inclination to do it: make it clear that you’re available to mentor people through issues. Make yourself available on something like IRC or Gitter, as people prefer live chat to the (perhaps more intimidating) communicate-via-Github-issue route. Make it clear: you won’t be facing the wolves alone!
The above leads directly into the bus factor. For those unaware, the bus factor is how many people need to be hit by a bus before your project dies. In addition to spreading knowledge and enthusiasm about your project, please be sure that:
At least one other person has commit access to your repo if you’re gone, and upload access to wherever your project is deployed (e.g. Hackage).
Set up a fallback plan if you aren’t available, either short term or long term. Consider having an open source will
Ideally make sure others know the code base well enough to maintain
This is the most depressing part of the guide, which is why I’ve left it till the end. There will ultimately be people who interact on an open source project in less-than-ideal ways. Figuring out how to respond to them is difficult to say the least. By identifying the behavior, and having standard responses, I’m hoping to be able to depersonalize it a bit. Furthermore, perhaps by writing this down, those interested in participating in open source will learn some behaviors not to demonstrate themselves.
This one is all too common. Writing a perfect bug report is hard. You need to figure out all of the context you need to provide, without providing a wall of text. If you err on either side (too much or too little), you’ll waste somebody’s time. Figuring out the balance is hard. If you’re new to reporting issues, explain as such, and be open to getting asked to rephrase the bug report and significant constructive criticism.
Keep in mind: you’re asking for help from someone, your goal should make it as easy as possible to provide that help.
I won’t waste time on redefining the XY problem, Wikipedia defines it well, plus a good thread on Stack Exchange. The XY problem is usually a direct result of trying to be respectful of people’s time, and not bore them with “unnecessary” details. Unfortunately, in the XY problem, it often backfires.
There’s no sure-fire way to completely avoid it. If you’re trying to figure out how to concatenate two strings, you don’t need to give a backstory on the business goals of the app you’re writing. By contrast, if you’re trying to read a file into a textual value, and have figured out how to read it as a binary value, don’t ask “how do I convert a binary value into text?” Most likely, the broader scope will reveal better answers.
I believe the term was originally crafted by Amy Hoy in the blog post Help Vampires: A Spotter’s Guide. Again, I’ll pass on redefining the term here, as that blog post does a great job of it. There’s a difficult line to walk when dealing with help vampires. On the one hand, you want to foster a community where people are able to ask questions and help each other. On the other hand, a non-stop onslaught of tedious questions with no end in sight can crush the spirits of contributors.
I can’t say that I have a perfect answer to dealing with help vampires. Education about the problem is great, but by their very nature, the help vampires are least likely to see the educating material. Ultimately, it seems like there are two ways to deal with the problem:
Ignore it and let it fester. Contributors may end up offering help to the vampire, get sucked dry, and lose momentum on the project. Alternatively, no one may answer the help vampire, giving the project the (unfair) appearance of being unhelpful to struggling users.
Address the problem head-on, and explain that the person in question needs to take more responsibility for solving their own problems. This is harder to pull off, but ultimately is worth it. Here’s a sample wording paraphrased from a real-life example:
This doesn’t sound like a bug or soluble issue for the project maintainers. Instead, this sounds like a request for consulting or assistance. You might try an IRC channel or a Slack community to see if someone can help you.
I mean this with no malice: Please keep the issues you file on GitHub limited to actionable issues for the people working on the project. We’re here to improve the project. We cannot provide help with open-ended project work. We are here to work on stuff that helps all users of the project. If I fix a bug, that helps me and helps everyone else using the project. If I help you with a specific, non-project-related issue, that doesn’t help any other users users. I understand you probably didn’t know this as a lot of these norms in open source are unspoken and unwritten, so I’m trying to lay out some of it so that you understand better going forward.
Some users feel that they are entitled to some kind of solution for their problem. Part of the goal for maintenance level is to set these expectations correctly. As a semi-concrete example, imagine that operating system XYZ seems to behave differently than many other OSes. You don’t use XYZ, and you’re not particularly interested in herculean efforts to make your project work for it. You may receive a stream of complaints requesting/insisting/demanding that you look into these issues.
Set expectations. State in the README that there are known issues with XYZ. Explain that it requires more effort to support that configuration than you have. And if you’re not inherently opposed to XYZ support, mention that having a contributor on the team take responsibility for XYZ support will help significantly with getting it better maintained.
Do you like this blog post and need help with industrial Haskell, Rust or DevOps? Contact us.