15 December 2024

High maintenance cost of not contributing upstream

Open-source is a great start for your business or product. It’s a solid base that you can customise to your heart’s desire. This post focuses on what to do with your code changes. In this post I’m also referring to them as patches and features. There are two general approaches:

  • Keep your patches to yourself (downstream)
  • Contribute your patches to an original project (upstream)

As it usually is: there is no silver bullet, it is a spectrum and the correct answer is “it depends”. The most crucial is whether you need to update along with an upstream.

Keeping a change downstream

It implies that you develop your feature in isolation from an upstream. Thus, you don’t need upstream’s approval and you don’t rely on upstream’s processes. This way you get a faster development cycle. Definitely a plus, when you need to release a product as soon as possible.

Since you’re not sharing your implementation, your product has a unique feature or at least has a higher chance of it being unique. You have to be careful with this one, because a licence might require sharing your source code. Even so, making your code available to your customers is not the same as contributing it upstream.

Those positives were rather obvious. The negative part is counter-intuitive: development cycle is significantly slower after a breaking upstream update. Upstream code base is a running target. Upstream developers are blind to your changes, so they are going to break your code even if they don’t intend to. There is no way for them to take care of your feature. It means that you have to integrate your change every time you’d like to merge upstream’s update. The most negative part about it, you have to be an expert in every system that breaks your feature. Usually, this is a much wider scope than your feature.

There are file systems that are developed alongside with Linux, like XFS, Btrfs and at the time of writing Bcachefs. Each of them works with the newest release of Linux, because they are part of Linux. ZFS on Linux is out of tree project. This means that ZFS has to adapt to changes in the newest Linux release. Because of this it’s usually not possible to run the latest kernel on release with ZFS.

QNAP has multiple patches over upstream ZFS. They’ve implemented some features earlier than upstream ZFS, but now they have implementations that differ from upstream. It adds maintenance burden and user confusion. In case of larger block sizes it’s also a worse user experience.

Upstreaming a change

There is a word to describe bringing your changes to an upstream - contribution. It’s often though that contributing your change is a noble thing for ones with a pure heart. You share your creation with the world free of charge.

Well it’s somewhat true, but it’s definitely not just that.

A contribution to a project is also a burden for maintainers. First, they have to review a change. If it’s not up to the project’s standards they might guide a contributor. After finally accepting the contribution, they have to maintain it, or help you do it.

This is the part that pays off for sharing your unique feature with an upstream. Upstream maintainers are not free labor, no one has to develop your feature for you. But your feature is a part of a bigger picture, maybe of the project’s test suite. It’s visible. When some other part of the project breaks your feature, it’s going to be known. Most probably, you still have to work on integrating your feature into new version of a project. Now it’s a shared responsibility. Which make it easier for you to focus on a domain of your feature, not everything it touches and touched by. Working with an upstream project more requires less expertise in an upstream codebase.

Downsides:

  • Longer initial development cycle: feature design coordination, approval, upstream release cycle.
  • You might up developing more to adhere to upstream’s standards and requests. For example, your implementation might be too tailored for your needs, you’d need to implement a more generic solution for a feature to be approved.
  • You don’t have complete control over your feature. Maintainers or other contributors might change it in ways you don’t like.
  • Possible rejection of your contribution.

How to choose

Keeping a feature private and contributing it from the get-go are ends of the spectrum. There are plenty of options in-between.

If you’re planning to keep your product up-to-date for a while, I strongly suggest working with upstream.

If it’s one-off feature that you don’t provide to you customers, or don’t intend to update, consider how useful it is to other users.

If you wish to contribute, try to estimate how useful your feature is to the project, and how does it impact upstream maintainers. Value that feature brings to upstream maintenance burden ratio. Both are difficult to measure, but sometimes the gap is obvious.

Making open-source development better

Reach out to an upstream early in your development cycle. It might be anything from an idea discussion or a poll to a proper Request For Comments (RFC). It’s okay to have your own downstream development to explore the problem, but it should not stop you from reaching out. This might bring other perspectives, like-minded contributors or even a sponsor.

When there is an approved design, or at least a design doc, there is a bigger chance that your initial design is going to stick, comparing to keeping it private.


This post is inspires by the episode 225 of 2.5 Admins podcast