Often, deployment is an afterthought. We build applications, and hit F5 from Visual Studio to test if they work. Eventually, someone has to figure out how to deploy that application into different environments. And depending on the application, that can range from being an easy job to a task of monumental complexity.
There's no quick fix, but hopefully some of the strategies below can help to make deployments easier.
Designing for deployment
During the course of building an application, we make decisions about frameworks, components, and application architecture as we build (or prepare to build) features. During these times, it's important to also think about how these decisions impact upon deployment. Ask questions like:
- Where will the application be installed?
- How will we pass different configuration options depending on which environment we're in?
- What assumptions should it make about the machine it runs on? What constraints are there?
- What OS services and third party dependencies is the application going to need? Who's going to install them?
- In what order will components need to be deployed? What dependencies are there during upgrades?
- How will we handle subsequent releases/deployments?
- How will this brilliant idea work in production?
- How will the operations team diagnose problems in this feature?
Ignoring these issues is a great way to guarantee pain at deployment time.
Automate what you can
Not all parts of a deployment can be automated, but that doesn't mean you should give up. If you can't convince your DBA's to let you automatically execute SQL migration scripts in production, that doesn't mean you shouldn't attempt to automate your web application deployment. A mostly-automated deployment is still better than a manual deployment.
Octopus includes a manual deployment step for this reason. You can run a series of automated steps, wait for a human to perform an action, and then continue the automated steps.
Follow established conventions, or create your own
Following conventions, or creating your own where none exist, can be a great way to reduce the amount of work involved in automating deployments. In other words, practice DRY. Some areas you can try to follow conventions around are:
- Storing all configuration options in the same place (e.g.,
appSettings), and accessing them the same way
- Having all Windows Services installed the same way
- Installing applications to a standard path
Make your applications self-deploying
Rather than relying on your deployment tool of choice to perform the bulk of the configuration and deployment work, consider making your application deployment-aware. For example:
- Give your Windows Service projects the ability to install/update themselves
- Give your persistence layer the ability to determine whether the schema is up to date, and to apply any migrations needed to update it
Making your application "self-deploying" can have great benefits, and decouples you from your deployment tool.
In Octopus, we invoke a
Deploy.ps1 script when we install your application. We pass configuration variables into this script depending on the environment. Ideally, this script could be as simple as telling your application to deploy itself with whatever configuration parameters are necessary. At the very least, this script should work outside of Octopus.
Don't assume the application is fixed in concrete
Sometimes questions like the following arise:
We have a component that [[does something that probably isn't a very good idea]]. Does the deployment tool support [[Rube Goldberg feature that works for this very strange use case but wouldn't be very useful for everyone else]]?
Instead of trying to "deploy around" the problem, sometimes a better solution is to reconsider how the application works. If you're faced with a problem and the solution feels overly complicated, don't rule out the possibility of redefining the problem by changing the application?
This isn't always possible, of course, but sometimes it's more possible than you might at first think. Sometimes it just requires talking to the right people.
Aim for just one deployment procedure
Sometimes it's tempting to come up with many different deployment procedures based on the kinds of changes being deployed. For major deployments, do blah. Just changing some content? Robocopy these files. Didn't change the database? Don't do XYZ.
Instead, try to create a single deployment process that can run from start to finish no matter what kinds of changes you've made. If a deployment step doesn't need to happen, the process should be smart enough to not run it, or run it in an idempotent way - that shouldn't be a human's responsibility. It means you've only got one procedure to test, and by running through it consistently it will make the bigger, scarier deployments more reliable.
Automating deployments for large applications can be a hard and time-consuming process. But it's a process that can be made much simpler if applications are designed to be deployed in the first place.