Strictly separate build and run stages
What problem are we solving?
Builds should be repeatable, trivial, and boring. If you can build your application twice in a row on different servers and get different results than you have a problem.
Additionally, the build should be hands-off. If your build or release process relies on humans clicking buttons inside an IDE then you have a problem.
Previous building blocks
We saw in Codebase that each repository should be able to generate a single artifact - no more and no less. This principle follows on logically by stating that just as development isn’t done in production, neither is building. For a given input, in this case the specific version of your repository, you should be able to generate a predictable output.
If your output is dependent on something that isn’t included (either by reference or value) in your repository then you have a serious problem. A common situation is having a “blessed” build machine, containing separately installed libraries or other dependencies.
Why wouldn't you?
I've been guilty of this one myself. With AWS Lambda, for example, its actually far easier to deploy code from Eclipse than it is to do so from the command-line, and during pre-release development and testing I've been known do right-click deploy when I shouldn't. It worked too, except for that one time that I uploaded the project over the wrong endpoint because I wasn’t paying attention, so … yeah.
Taking the time to find, build, or use properly automated solutions is worth the time.
Once you have truly repeatable hands-off builds going on, you can set up pipelines to make your life easier. Heroku really shines here - you can easily create builds that result in fully running systems on every Pull Request as well as a staging environment that updates whenever you merge into master. I will talk more about these options in a future Heroku discussion, but whatever toolset you use, having a hands-off reliable build opens up all kinds of awesome opportunities.
The best part about having a good build process that reliably outputs everything you need - other than environmental concerns - to run the system, is that you can get the other processes “for free”. We’re starting to see real benefits from the 12 Factors building on one another. Since you’re cleaning defining external resources, and can generate builds at will, you should be able to generate dev/test/stage/production environments without much of a headache.
I realize that we’ve spent a lot of time talking about the build stage. The main reason for that is that is that once you’ve got the build down, and you’re storing your configuration in the environment, doing a release is No Big Deal - which is exactly where you want it to be.
Also note that for SaaS applications, the build should statically link everything. The gal is to create an executable that behaves identical wherever its deployed, other than responding to configuration through environment variables. If your product is relying on other software to be installed on the machine, you’ve created unnecessary problems for yourself.
What does it take?
In a new project this is simple. For porting over existing projects, you’ll need to revisit everything that you looked at during config and make sure that:
1. You included services currently provided by internal IT that live outside of the work defined by your repository, and
2. You didn’t make any assumptions about how those services would be delivered.
Hopefully you can see the benefits now, but as we’ve seen with [[configuration]], this discipline will really start to open up opportunities as we continue to move down the 12 Factor list.