Let's say for the sake of argument that we would like to do feature-oriented releases.
Why We Might Do So
There are a number of reasons we might choose to do a release based on its contents (features) rather than a date. These include, for example:
1. because a customer is blocked by a bug and cannot wait until the next release
2. because a customer or potential customer is blocked by a feature that is required to complete (or continue) their development
3. because we want to show a customer or potential customer that we can turn around requests quickly
4. because a feature is likely to need change and we need to provide an early copy to customers (some or all) to collect feedback
Notes on Speed
An implication behind feature-oriented releases is that they are likely to be more frequent than date-based releases. This is mostly because date-based releases generally include several features, and are typically larger overall change.
Number of Versions in Field
There are some downsides to doing feature-based releases. In particular, it winds up with far more releases in the field. In a situation like a hosted web application, where the company controls production, this isn't a problem. In a situation where software is shipped and upgraded by customers (consumer installed software, app-store-based applications, many enterprise applications and libraries), the number of releases in the field can be a concern. Too many releases in the field causes a major drag on future releases, mostly due to upgrade and similar tests having many more variables.
There are a few ways to handle this, from aggressive release end-of-lifing to support policies forcing upgrades. This is a bit of a delicate line to draw with customers, though.
Let's assume that the time to actually implement, debug, refine, fix, test, and release any one feature is roughly the same regardless of what type of release we're doing. The way to increase the speed of releases, then, is to reduce the other work that goes into a release. This other work can be characterized as:
1. integration of other features, in particular of multiple in-progress features
2. documentation, including release notes and updates to presentations, marketing materials
3. availability notification of releases (e.g., upload to a customer portal)
4. once-per-release validations and measurements (e.g., performance tests, or packaging validation)
Of these, by far the largest are numbers 1 (integration) and 4. Number 1 in particular is often a large unknown: two features that are fine alone may not integrate cleanly. When both are still in progress, they are likely to integrate even less cleanly. For number 4, with very frequent releases, it can often be necessary to perform these validations once per several releases, depending on what they are for (e.g., do in depth performance testing every 5th release or if there is some concern about the specific feature being released).
Use of Branches
One of the most common problems with a feature-based release is when there are multiple features in progress. Feature A may be complete and ready to go, but feature B isn't ready and the tree is unstable as a result. Feature A is in essence held hostage by feature B. For this reason, doing feature-based releases, we usually designate a "release branch" (typically main or head) and "feature branches" (one per feature). The workflow for a feature looks like this:
1. create a branch for that feature
2. do all the feature work
3. merge from the main release branch (to pick up any changes or other features that were finished while you were working on this one)
4. fix/test your feature
5. repeat 3 and 4 until complete
6. merge to the main branch
7. sanity check and release
This adds some branch management overhead, but pays off in the ability to keep a stable, releasable main code base.
When working with multiple releases and in particular with APIs where deprecating features or APIs is a consideration, special attention should be paid to how many releases occur before a deprecated element is removed. As with all release types, the goal is to balance simplification of development (by removing support for deprecated items) with customer ease (not having to rework their integration). One approach is to do periodic "roll up" releases that remove deprecations from previous releases. These are frequently the releases to which you will push your slow-upgrading customers, who are likely to skip interim releases.
For example, we might release like this:
4.1: new feature A
4.2: new feature B
4.3: deprecate old feature X
4.4: new feature D
5.0: roll up release, remove deprecated feature X
5.1: new feature E
5.2: deprecate feature Y
5.3: new feature F
Feature-based releases have a number of benefits. They're also a very bad idea for some situations and some groups. Take a look, figure out if it's right foryou, and good luck either way!