Much of the stability, reliability, and success of a software product depends on how we effectively create, manage and maintain the software environments throughout the software development life cycle.
In a software engineering context, an “environment” refers to the complete set of hardware and software components (tools, resources, systems, and services) that we utilize to build, maintain and scale the software product. This may include but is certainly not limited to a real or virtual machine, with a specific operating system, the database systems, the development tools (e.g. IDEs, compilers, libraries), the data management solutions, external/internal services, cloud services, and tools for different other purposes 🔨
During my initial days as a software engineer, I found myself asking the following questions quite a few times:
- Why do we need separate environments to build a software product?
- Can’t we just have one environment where we can build, test and ship the entire product?
As I progressed in my career, I started to understand the importance of having different environments, and observed how each environment was set up while keeping in mind specific purposes and flexibility. When considering the complexities of the components that make up the environments, a question arises: how we can effectively manage those environments, and what strategies can we take to turn this environment-management activity into a smooth sailing process? The answer is by using the power of automation and services offered by the cloud providers, wherever possible.
The environments which we will talk about are the Development Environment, the Test Environment, the Staging Environment, and the Production Environment. Some teams may have some additional environments or they may use some different names for these environments. But mostly, these four are the environments through which the entire SDLC spans.
In the case of DevOps implementations, the environments will be a part of the DevOps pipeline and the selection will be configured based on the merged branch or the branch tags 🔖
Managing Development Environment
The “local environment” is the individual developer’s desktop/workstation where the code is written, bugs are fixed and unit tests are run locally by the developer for his self-contained part of the feature (in an isolated way). The changes made in the local will not influence or hinder other developers’ work as well as it will not get affected by changes made by other developers.
From the local, the code is then pushed by the developer to the team’s shared development environment. There the code from other developers will also be merged, and together in this environment, it will be checked whether a developed feature in the current iteration/sprint is working as expected or not. The following are some important factors to consider when managing a development environment:
- Ensure the required services (internal/external) are installed, initialized, available, and in the desired state.
- All dependencies and artifacts are installed/downloaded/resolved correctly.
- Right folder permissions are in place.
- Make sure the logging systems are set up correctly to facilitate local debugging of issues quickly.
- Wherever possible, automation scripts should be used to quickly perform partial or complete environment setup, or to perform quick teardown/recreation/update of an existing development environment.
- Communication with remote servers and database systems is set-up correctly.
- With every code push in the repository, integration tests run to ensure the changes aren’t breaking the build.
- Ensure the environment is in a clean state while building the complete source code present in the repository.
- Create and use containers wherever possible.
- Create and maintain clear and concise documentation on the environment setup (e.g. in the README file).
- Maintain a common standard environment-based application configuration in a separate file (e.g. in a ”.env” file) and allow the developers to change/overwrite it according to their requirement.
Managing Test Environment
This is a very important environment to have in the software development life cycle and needs a high level of attention. The main objective of having this dedicated environment is to experience and explore the product through the eyes of testers, who find issues and reveal problems about the product-under-test 🔍
Automated checks are also performed in this environment to ensure that existing functionalities are working as expected. Once the development team becomes confident of the feature in the development environment, the code is then pushed to the test environment for the testers to test the product. Many teams go for multiple test environments. Some key things to consider while managing the test environment are as follows:
- Have the test environment configured in a way that performs quick, frequent, and automated parallel tests execution. These checks should be at the user interface and API level to provide quick feedback.
- Have test data management solutions in place in order to provide new / recycled / refreshed / masked test data whenever required.
- Remove, recycle or refresh the environments and resources (using automation scripts) as and when required.
- Continuously monitor the environment(s) for availability and usage.
- Integrate communication tools (like Slack) for notifying automated tests results or any environment-related issue to the team promptly.
- Ensure the devices, servers, resources, network, tools, and services are working as expected.
- Ensure that the containers (like Docker) and orchestration tools (like Kubernetes) are used for tests, they are in a ready state.
- Use IaC (Infrastructure-As-Code) to provision and configure the environment.
Managing Staging Environment
The “Staging” (sometimes also referred to as the Pre-Prod) environment is created to mirror the actual production environment as much as possible. The main goal of having a staging environment is to check the installation, configuration, and services of the software before it is put into the production environment for the customers to use. In this way, any issues found in the staging environment will not have an impact on the real users or customers who will be using the product in the production environment.
Though it is impossible to make the staging environment resemble the exact production environment, an attempt should be made to make it as identical as possible with the goal to find issues before the users encounter them. In addition, any upgrades can be tested in the staging environment. You first need to filter out upgrade issues before those upgrades are deployed into production. Some things to consider while managing the staging environment are as follows:
- Have the staging environment be a very close match to the production environment.
- Ensure the environment is accessible only to the intended people and not to the end-users. This can be done by whitelisting IPs and usernames.
- Perform data refresh whenever required.
- Have automated scripts to recreate or update the environment whenever required.
- Ensure the monitoring and alerting systems are running smoothly.
- Ensure the network endpoints and databases have the same configuration as the production, but are running with dummy data.
- Create and use containers and container-orchestration tools wherever possible.
- Ensure the presence of the capability to roll back deployed code quickly and safely.
Managing Production Environment
The “Production” (sometimes called Live or simply Prod) environment is the place where the real customers/users interact with the software product 👩💻 Some key things to consider while managing the production environment are as follows:
- Only the necessary services/applications should be used and there should be redundancy in place.
- The environment should be up all the time and the downtime should be minimal.
- Disaster Recovery mechanisms and solutions should be in place.
- All product features can be present in the production environment, but capabilities should exist to release them based on customer demand.
- Efficient patching mechanisms should be present in order to update the production components with zero user impact.
- Production level access should be provided only to people who actually need it and permissions should be configured accordingly.
- Ensure the logging, monitoring, and alerting systems are working correctly.
- Ensure comprehensive and updated documentation of the production environment is present.
Creating and maintaining environments is an important task and it requires collaboration and shared responsibility between the team members. If the environments are managed and maintained efficiently, the software product is due to a success 🏆