In software, there isn’t one answer that fits every situation or every project. The number of people on the team, the complexity of the project, and even the technologies used can all vary. However, what is true in every case is that if you leave deployment to an environment as similar or identical to production as possible until the very end, you’ll run into a lot—an awful lot—of problems.
You should deploy to a production-like environment as soon as you have a finished, complete feature, even if it’s a simple one.
Even if we have a fantastic integration environment and excellent configuration management, that doesn’t guarantee everything will work wonderfully in production. You could write an entire book on this topic, depending on the nature of the project and even the team. Yet I’m afraid the final deployment is almost never considered until… the end! That’s when we can get a lot of surprises.
If we don’t do this—if we don’t think about deployment from the beginning—the gap we’ll face at the end of the project, when we think everything is almost finished, will only grow wider.
An extreme example is developing the project on the end customer’s own machine, only to discover that outside that machine the project requires a complete reengineering (…). In software, this is almost a cardinal sin, just like testing against production databases or devices at end-customer sites. Sure, if it has to be done, do it when there’s no other choice—but at least be aware of the possible consequences.
These are the reasons why I believe a project should be deployed to a pre-production environment as early as possible.
Usually, a production environment (the environment the client will ultimately use to run our project) has nothing to do with the local development environment we tend to use. That’s an obvious, even glib, thing to say, but until we suffer the consequences, we don’t realize that the SDKs you have locally but won’t have in production may turn out to be essential; the production database configuration may differ from the one you use in development (or may even be a different version); and the final server or destination may have nothing in common with the developers’ environment, just to name a few examples.
It’s also common to miss certain bottlenecks because everything runs smoothly on your local machine, where it’s all on one computer and database connections are local, if you use a database at all. You don’t account for the latency that may occur in production if the database isn’t local, is accessed remotely, or even uses a shared database engine, as often happens in various environments.
For a web application, you may not notice performance problems when loading a simple page locally if your CSS and JavaScript files aren’t minified and concatenated. That can be a problem in a real environment.
Even in high-level environments like .NET, some things may work perfectly in debug mode and fail in an unexpected way in release mode. Surprised?
On your local workstation, you usually have all the information and logs for anything that happens in the system close at hand. Have we made sure the same level of tracing exists in production? When something fails, will we have the tools needed to find out what’s happening?
So far, I’ve only briefly discussed what could happen once the project is deployed. But will we be able to deploy it as many times as necessary? In other words, we need deployment instructions that specify:
- The base software that must be preinstalled, including its versions and configuration (such as Apache, IIS, Node, SQL Server, MySQL, Nginx, frameworks, Redis, and so on).
- The exact location where all project artifacts should be published. This is vital when we expect to publish the project for more than one client. Nothing is worse than having some things scattered here and there; depending on each client’s machine, this can drive whoever is responsible for maintenance crazy (which means a complete lack of productivity).
- The final tests that will assure us that everything is up and running. These aren’t unit or integration tests, but tests—even manual ones—to ensure everything should be working correctly. These are commonly called validation tests and, depending on the project, the end client may perform them to give the system final approval.
All of this may sound a little gloomy, but it’s common for at least some of what I’ve described to have happened to you at some point.
The way to avoid this is to see deployment not as something done at the end of the project, but to treat the deployment guide as another project artifact from day one. That way, the guide and its updates throughout development let us make solid progress from the start, ensuring that the features we’ve built so far work in both our development or integration environments and the final environments. If we’re lucky enough to need to deploy the system for twenty new clients, neither you nor the person in charge will have to think too hard, because everything will be documented in the deployment guide.
In my opinion, having deployment instructions for any project is a sign of quality.
Who hasn’t been asked at some point to set up a project using its source code and nothing else? Terrifying.