In any deployment process, there's a tension between:
- The need to make changes to the deployment process/configuration; and,
- The desire for deployments of a release candidate to have some consistentcy between environments
For example, suppose that as part of your deployment process, you need to configure a special setting for an IIS website. You've written some PowerShell to do this. You deploy the release (let's call it "Release 1.1") to a Test environment, and it looks like the release is ready to go to Production, once the right people have signed off.
While waiting, you decide to make some tweaks to the PowerShell script; perhaps you find a new way to make the IIS change with less code. You make a new release ("Release 1.2"), and deploy that to Test. It seems to work OK, but you aren't 100% sure - the output wasn't exactly what you expected.
Suddenly, you get the green light to deploy "Release 1.1" to production. Would you want it to run the experimental PowerShell you've just been working on, or the old, tried-and-tested PowerShell that originally ran when Release 1.1 was deployed to Test?
Snapshots
In 2012, Octopus introduced snapshots as the solution to this problem. When "Release 1.1" is created, we take a snapshot of:
- The deployment steps that make up the deployment process, and
- The variables that make up the project configuration
This way, you can make changes to your heart's content, and be confident that the old release wouldn't introduce any unexpected changes; what happens in Test is what happens in Production.
Snapshots weren't the silver bullet I'd hoped when we first introduced them though. They broke down in different scenarios:
- Say you've never deployed to Production before (a project in its infancy); now, before you go to Production, you realise some extra steps or variables are needed. There's no way to add these if we rely only on the snapshots.
- Your API key for PayPal changes, or the database server is relocated. The old releases would still use the old API key and the old database server; that's pointless.
To work around some of these issues, we added a button to import the latest variables for the project into a release - effectively overwriting the old snapshot. It was limited to variables, however. If you add a new deployment step, you still have to delete the old release and create a new one.
The biggest limitation to snapshots, though, is that they were linear. There is no way to "branch" the snapshots - say, to keep a "1.x" version of a deployment process, and a "2.x" version.
Channels
In late 2015, we added Channels. Channels were originally intended to help us support branching, but we quickly found a lot of other uses for them:
- Hotfix releases, where some steps and environments are skipped
- Evolving the deployment design: you can completely add or change steps on a per-channel basis
- Handling feature branches and new streams of releases
- Temporarily disabling steps or variables (just assign them to a channel you don't use)
Are snapshots needed?
When discussing plans around snapshots and how the apply to multi-tenancy in our upcoming release, we came to the realization that channels actually solves many of the same problems that snapshots were originally introduced to solve - only better.
In the example above, the "tried and tested" PowerShell step might belong to a "Main" channel, while the "new and improved" PowerShell step might belong to an "Experimental" channel. Release 1.1 would be a release on the "Main" channel, while 1.2 would be on the "Experimental" channel. You could keep iterating on new versions of both, and be sure about which one would run in each release.
Channels works better for this than snapshots, because you can be granular in how they apply. Out of all of your variables, you might only care about "snapshot" behavior for a few of them. API keys and database servers, of course, would always use the "latest" variables. But a small handful you might want to keep (e.g., different file paths for your 1.x code and your 2.x code). You can scope these variable values to a channel to achieve this behavior, without snapshots.
Snapshot behavior can also be very annoying. If you're experimenting with a new script by deploying to a Test environment, you have to keep creating new releases just to test each change. It would be so much easier to use an "Experimental" channel and not use snapshots. You can even configure a lifecycle so that your "Experimental" channel releases can never go to Production - it's just so powerful.
This is pointing to a conclusion: snapshots appear to be obsolete. I just can't come up with any scenarios that snapshots handle that channels couldn't.
Removing snapshots
In 3.4 we're considering removing snapshots completely. The reasons to do so are:
- Anything snapshots can do, channels can do better
- It's wasteful for a product to have two ways to achieve the same goals
- Snapshots make experimenting on changes to the deployment process difficult
- They are confusing to new users; channels are a feature users only see if they seek it out, but otherwise stays out of the way
- If we were starting from scratch today, we'd just do channels and not do snapshots
- Snapshots are making features like multi-tenancy difficult to reason about (are tenant variables included in snapshots)?
If we did remove them, we'd need to think about:
- What does the upgrade process/compatibility look like (since people currently rely on the behavior)
- How do we help people to do "roll backs" if they forget to test changes on a channel - improved source control integration seems like a better approach for this.
- Education. Snapshots are at least easy to explain; we'd need to find a way to simply explain how to use channels to achieve the same scenarios.
What do you think? Would you be glad to see the back of snapshots? Can you think of a scenario that snapshots supports that channels couldn't?