How Often Should I Release My Software?

(learn about this date format)

A lot of my software doesn’t need to be released. Most of my software already lives in public Git repos. If someone wants to use one of those pieces of software, then they can just clone the repo. Take this Web site for example. I don’t really see a reason why I should give this site a version number or tag specific commits as releases. Whenever I push a change to this site’s main branch, I also build the site and update the copy that’s at jasonyundt.website.

That being said, there is one piece of software that I do want to start releasing. Here’s the question: how often should I release that piece of software? Before I was able to answer that question, I had to think about these two questions:

  1. What does releasing too quickly look like?
  2. What does releasing too slowly look like?

What does releasing too quickly look like?

When software is released, it creates more work for people who use that software. Package maintainers have to update their packages, and end users have to install updates. Updates take time and energy, so updates need to benefit users or else they won’t be worth doing. Imagine if I released a new version every time I pushed a commit to the main branch. You would end up with updates that literally don’t change anything from the end user’s perspective. For example, consider these commits:

If a new version had been released for each of those commits, there would literally be no benefit to updating. It would just be a waste of time.

What does releasing too slowly look like?

When a piece of software isn’t working for me or lacks a feature that I want, I often try to contribute to that software. I like that strategy because it’s a really direct way of solving the problem, and it gives back to the community. Unfortunately, that strategy doesn’t always work.

For example, in February of , I was trying to write a pre-commit hook that required Python 3.11 or later. For whatever reason, building Nixpkgs’s pre-commit package with Python 3.11 required building CFFI with Python 3.11. At the time, one of CFFI’s tests was broken on Python 3.11. OK, so if I fix that test, then it will allow me to use pre-commit with Python 3.11, right? Not so fast! CFFI had already been fixed. The fix was in the main branch, but the most recent release didn’t contain the fix because it was too old. I wanted to make a CFFI release come out sooner, but I didn’t have any power to make that happen. Additionally, the fix was already in Nixpkgs Unstable, but the most recent NixOS release didn’t contain the fix because it was too old.

That’s not the only time something like that has happened to me. Here are some examples:

How I plan to prevent those situations from happening

Here’s how I’m going to decide when to do releases:

  1. Keep track of the number of unreleased commits. An unreleased commit is a commit that’s in the main branch’s commit log, but isn’t in any of the releases’s commit logs.
  2. If there’s thirty or more unreleased commits, then do a release.
  3. If there’s an unreleased commit that’s over three months old, then do a release.

The goal of that plan is to make those previously mentioned scenarios very uncommon without requiring much effort on my part. First, that plan makes releases with no user-facing changes unlikely. My assumption is that most of the time releases will contain thirty new commits. I haven’t run the numbers, but my hunch is that I add at least one new feature or one new bug fix every thirty commits without even trying. If somehow I do merge thirty commits without creating a single user-facing change, then that’s OK. If I somehow only change a single comment over the course of three months, then that’s OK. I can do a subpar release every so often.

Second, that plan empowers contributors to make releases come out sooner. If a feature gets merged, and you want that feature to get released ASAP, then start submitting patches. The more good patches that a contributor submits, the sooner the release is likely to come out. Additionally, if changes don’t make it into the main branch fast enough, a release will still happen eventually. It might take me a while to realize that we’ve hit the three month mark, but it will happen eventually. If for some reason I don’t do that release, then feel free to bug me. If I don’t respond to being bugged, then I’m probably not doing a good job at maintaining that project. Fork it, and do a release yourself.

Another advantage of that plan is that it doesn’t require any thinking. I’ll be able to write a tool that will automatically tell me when I need to do a release. In theory, I could have come up with a more complicated plan that completely prevents pointless updates, but that would require more thinking on my part. The more thinking I have to do, the more likely I am to make a mistake. Thinking about whether or not I should do a release would also take time away from other more important tasks.