Liam White
The Open Source Project Maintainer's Guide

Have you found that there are too many high quality contributors wanting to help you fix issues and deliver their code directly to your source repository? Here's a list of steps you can take to cut back on those pesky contributions and help everyone know the exact type of leadership you want for your project.

Use a source control mechanism other than git

Use Bazaar, Mercurial, SVN, CVS, or even whatever SQLite is doing. Since the industry standard is git, this will make sure your contributors are really confident they want to contribute to your repository, as they will have to install and configure a brand new version control system which they are guaranteed to be unfamiliar with.

Only accept patches on the mailing list

There is absolutely no benefit to having fully automated tools like code linting, spell checking, per-platform builds, and automatic tests run for would-be contributors to your project, to allow them to fix potential issues they may have on their own time. No, that would simply be too easy, and contributors must prove their worth by emailing patches which may follow the style of the project, and then having a spirited discussion with maintainers over email to fix code style and formatting errors by submitting new patch sets.

This also preserves the true job of maintainers: to manually do tasks which should have been automated away by now. It gives us a sense of value in our lives. Continuous integration is killing our jobs!

Require a contributor license agreement

Why should you be willing to accept anyone's code if you can't be sure that you can take it and relicense it however you want? It's their gracious gift to you, which makes it your property now.

Don't have community forums or leadership

There is no reason to have any place for community discussion about your software other than the mailing list you set up. No phpBB, Discourse, no Zulip or IRC, no Telegram or Matrix, and especially not Slack or Discord. After doing the calculations, you have decided you'd rather not have users who won't use mailing lists anyway. Plus, it frees you from the hassle of having to set up a steering group and a project-wide code of conduct.

Ignore detailed reports

A user report of bug in your project, a report filled with every relevant stack trace and log, perhaps even pointing to the exact nature of the problem, is simply not worth your time as a maintainer. You should completely ignore these reports, since such technical users will probably just follow up with a patch set to fix the bug, right? It's more important to spend your time reviewing changesets for formatting errors than responding to highly technical and detailed issue reports.

Systematically close old reports

A report being old means the issue was fixed, or at least no longer important, right? Just close that, since nobody bothered to respond to it for a month. It must not really be an issue. We can even add some handy automation tools to do it for us!

Prioritize features over bugs

There is no obvious value to clearing the backlog of bugs, since your stale automation will simply close them if they are not followed up on. Be sure to only spend time pulling and implementing code for features that you want.

Don't worry about the way your program crashes if you do something slightly unusual—it's not a big priority! And especially don't worry about your closed-source, paid competitor's software, which normally never crashes!

Wait for the big rewrite

That rewrite you planned years ago, which was going to fix all the bugs related to some part of your project, is still not here. Maybe you haven't even pushed the WIP to your repository. But it's in progress, you promise! So when new contributors send patches to fix bugs in the existing code, reject these immediately, because it would only cause you endless grief with merge conflicts in your own branch. Besides, features are more important anyway.

Merge half-baked patch sets

There is really no harm in pulling a patch set that has significant omissions or major bugs. This won't decrease the overall quality of your code, since you can just ask that contributor to fix it later once you realize the scope of the problem.

Bikeshed all user visible changes

It's perfectly normal to merge large feature branches without a second thought, perhaps without even reviewing them. But it is your sworn duty with your co-maintainers to make the life of anyone who contributes small usability tweaks to parts of the project as miserable as possible.

Only use outdated language standards

The current C++ standard is C++23, and C++17 is widely supported among toolchains used by your active users. But your project uses C++03, because two of your co-maintainers want it to work on their retro computers with the last toolchains which were ever released for them, and that's fine by you.

Spice up your syntax

Be sure to freely mix PascalCase, camelCase, and snake_case identifiers in your code. Use tabs and spaces, and vary the amount of spaces based on the file. Shadow variables to keep developers on their toes about which variable they are really referring to. Make judicious use of typos and grammatical errors in both your source code and comments. This gives your project a special touch of artistry.

Use an old build system

It's perfectly okay for your project to depend on autotools to generate its build scripts in the modern age. It's also perfectly normal and acceptable to pipe curl into bash to install all of the dependencies needed to build your project. To be honest, you are not sure why people keep telling you it's time to move on.

Compile slowly

Waiting for your code to compile is a rite of passage as a developer, and it builds character. Make sure you design your incremental rebuilds to be as slow as possible, since this filters out the low-quality contributors who won't have time to wait while testing their fixes.

Don't trust the compiler

Disable all the warnings, since they don't mean anything to you anyway. Errors are just unnecessary obstacles preventing you from achieving your perfect program. Don't let coverity or clang-SA complain about complexity metrics in your functions, either—in fact, make sure to copy and paste the code of trivial helper functions, since you don't trust the compiler to do inlining correctly.

Trust the programmer

Automated tests are for chumps. You personally guarantee your code is correct, and guarantee that nobody will ever edit it in a way that creates regressions. Therefore, you don't need to add any tests for it. Why would test coverage ever matter, if the code works in the specific scenarios you already manually checked?

Keep strong typing for the weak-willed

Reject dedicated data types whenever possible, and prefer using built-in data structures and type casting, since it compiles more quickly. Make code written in different languages have to interact both ways without automated bindings connecting the two. You can get bonus points for doing this for programs communicating over an IPC protocol. After all, managing the runtime errors when types are cast incorrectly is a true test of your skill as a programmer.

Only allow self-documenting code

There is never any need for code documentation. The function names, class names, and parameter names will completely explain everything and any programmer familiar with the code should be able to figure out what it does. The side effects, prerequisites and postrequisites for function calls, arguments, and return values are not important, and if they are, you'll know what to do with it.

Prefer spaghetti code to lasagna code

Make sure that the different parts of your codebase are as interlinked as possible. Cutting out a typical source file should require invasively changing at least 20% of the other files in the project to remove all the references to it. Having events and data flow up the hierarchy from the source and then down to the target is bad—the source and target really ought to be directly connected.