In my previous blog post I mentioned that I intend to begin a regimen of smaller, more frequent releases in my open source projects. Afterwards, I started thinking more about what this meant and how software release schedules work in general. This is the result.
Setting the stage
Three primary pressures affect software release schedules: speed, stability, and maintenance effort. All release regimens/schedules play these up to varying degrees, and like so much else in computing, they form a series of tradeoffs.
Speed
Speed is the desire for fixes and features to become available to the public as soon as possible.
- This pressure comes from all user types, especially those suffering from specific bugs or security issues, or who expend effort to mitigate features missing upstream.
- Technically, “development speed” includes the time & effort required to investigate, test & implement changes. In this case, let’s pretend changes roll in at a near-constant rate and that the question is just how often to release them.
- Taken to an extreme, this pressure would see every single discrete changeset released as its own version.
Stability
Stability is the desire to pick a released version/feature set and continue receiving bugfix-only releases for as long as possible, without having to upgrade.
- Not quite as many users clamor for this, though (to be opinionated) anybody with sense will at least consider it.
- In an ideal world, stability would have maintainers preserve a new release branch for every feature, backporting or forwardporting all bugfixes to every version affected.
Ease of maintenance
Ease of maintenance recognizes that (especially for open source) time is finite, and each active release branch adds overhead to the release process.
- It is possible to have ideal speed married to ideal stability (ignoring the communication problem posed by dozens of “active” branches) but it requires unrealistic effort on the part of the maintainers.
- Thus, every project implicitly or explicitly has a maintenance window (aka support window): a period of time, or a number of releases, within which bugfixes are guaranteed to be backported.
Examining tradeoffs
These pressures result in a few different release methodologies:
- Many projects emphasize ease of maintenance over stability, keeping a
single release line and never backporting anything.
- This allows for, but doesn’t require, a high speed.
- The maintenance window concept doesn’t apply here: it’s effectively zero length.
- Most other projects specify a maintenance window in number of releases
(e.g. “we support the most recent 2 release lines”), backporting fixes to
only those release branches.
- The amount of time a given release is supported is inversely proportional
to development speed.
- For example, with a 2-release window and an average of 1 feature release per week, a project would only have a 2-week support window. Not good for stability!
- However, a 2-release window and releases e.g. every month or two would be a much more reasonable support period.
- Maintenance effort is nonzero, but constant, scaling with the number of supported releases.
- The amount of time a given release is supported is inversely proportional
to development speed.
- Much less common is a maintenance window specified in time (e.g. “we
guarantee bugfixes for 6 months after any feature release”).
- Under this scheme, ease of maintenance is inversely related to speed (more releases means more overlapping support periods), and the size of the maintenance window is constant.
How this applies to Fabric
Fabric has gone through a few of these schemes over its history:
- In 2008/2009 I supported as many release branches as possible. Every bugfix
was backported as far as made sense - older release lines did die but it took
a while.
- This prioritized stability over ease of maintenance.
- Releases were not frequent - speed was slow to moderate. Ease of maintenance worsened as time went on, but not rapidly.
- A couple years ago, I found myself avoiding/delaying releases because the
maintenance burden had become a pain: speed was being sacrificed for
stability.
- To combat this, I moved to a 3-release maintenance window (i.e. while, say, Fabric 1.4 was the stable release, 1.2 and 1.3 got backports.)
- Stability thus went down, but because releases were still infrequent (once every 1-3 months) it wasn’t a major regression.
- About a year ago, I cut down further, supporting only 1 old release line (for
a total of 2.) For example, right now 1.7 is the stable release, and I
backport to 1.6 only.
- This moved in the same direction as the previous change: making releases and maintenance easier at the cost of some stability.
- Release scheduling remained loose, a month or more between releases.
- As of late I’m trying to amp up the speed (of merge to release, if not actual development.) The release methodology itself is not changing for now - 2 releases will still be supported.
The future
Where does this leave us? If I release all merged/triaged fixes weekly, Fabric’s support window will shrink dramatically unless I keep more branches open. As above, it’s not possible to be fast and stable and keep maintenance effort low.
However, much of this post assumes all releases are equal, or that bugfix and feature releases go out simultaneously (usually the case for Fabric.) This isn’t really required: I could e.g. release bugfixes weekly, but release new features every 2-4 weeks.
That mixed approach meets things halfway: actual bugfixes go out ASAP, but the support window remains a reasonable size. Being honest, even a 2-4 week schedule for feature releases would be a welcome change from my historical multiple-month wait time.
I’m taking steps to reassign time from my other responsibilities to open source work - so we’ll see whether this hybrid approach pans out soon.