From development to release
Development of any application always starts from with source code and finish with the application that is available for the users. Depending on the application’s type (web application, mobile or desktop application) a transformation from a source code to a final product can be different. But the stages of this process are the same. Let’s consider this process and the steps, that our source code goes through before it became the final product.
Let’s call this process — release process. The end product that is delivered to the user we will call artefact.
An artefact is a result of our build process. It can be a binary file, built js bundle or .ipa/.apk files.
The stages of release process
- testing of source code
- building an artefact
- testing of a build artefact
- storing of a build artefact
- deploying of a build artefact
Testing of source code
On this stage, we are working with source code. We are checking it with unit tests, e2e tests, run the linter to check the formatting of the code or/and run static analysers.
All, that we can check without building we should check on this stage. It’s usually fast checks.
- unit tests
- e2e tests
- static analysis
- calculate test coverage
Building an artefact
On this stage, we are building our project. This can be the compilation of our mobile application or building the js bundle for the web project. We are creating the final artefact, that will be delivered to the users.
A building of the Docker container is for this stage because exactly this Docker container will be working in our production and dev environments.
Requirements for the artefact
Our application has to follow 12 factors. For this stage the next rule is critical:
- split code and configuration
You have to be able to run you build artefact for both production use and alpha/beta testing. And if you need to reconfigure the access to the database or the API access parameters you have to be able to do this through the external configuration file.
This point is important for the next step. We will run automatic acceptance testing. Usually, for the acceptance testing we are using dev or beta environments, and for production env, we will use just another configuration, but the same build artefact (without rebuilding);
A litmus test for whether an app has all config correctly factored out of the code is whether the codebase could be made open source at any moment, without compromising any credentials.
If you feel unconfident here — please have a more in-depth look at this material.
Testing of build artefact
Once we’ve built our artefact, we can test it. As you remember, unit and e2e test are already passed, so it’s time for the acceptance testing.
For the web application, we can use selenium tests. To run them we have to run our application (e.g. run our Docker container) and execute our tests on this instance.
On this stage we also can run the visual regression testing: take the screenshots of the application and compare them with the screenshots of the previous version to find the diffs.
For the mobile applications, we can use Apium tests.
Storing of build artefact
When our build artefact is tested, we can store it. Usually, on this stage, we are confident, that our application is workable according to the test cases, what we’ve checked with auto-tests.
Depending on the requirements of the project we can store or not the artefact, which didn’t pass the testing stage successfully. For example, in the process of the visual regression testing, people have to make a decision — approve or reject the visible changes. In this case, we have to store all the artefacts to allow developers to make the decision.
We can store the artefacts in the different ways: Docker Hub, CDN, simple zip files on some file storage. It’s not crucial. Is it important to select storing method according to this two rules:
- we have to be able to specify the version and the link to the commit
- it has to be simple to work with the storage on the deploy stage
Between the storing and deploy stages can be other manual steps of testing and approving of the artefact. It is important that we are working with the built artefact, which is partially tested and will be used without the rebuild on the deployment stage.
For the web projects — an update of the web server. For the web or desktop applications — uploading to the application store or in any applications distribution place (e.g. sending to the publisher for the burning in the CDs 🙂)
On this stage we are working with the three entities: environment, there we are deploying, artefact, that we are deploying, and the deploy script, that we’re using for the deployment.
- Where? Environment
- What? Artifact
- How? Deploy script
We’re downloading our artefact from the storage. Config is storing in the environment. Environments know how to work with these two entities.
Good example #1. Web application, Kubernetes, Docker, Docker Hub
Kubernetes is our environment. We have Kubernetes configuration that contains all the settings of our application. To update our app, we update the version of Docker container and run the update command. New artefact (Docker image) will download from our storage (Docker Hub) into our environment (Kubernetes), and our built artefact will run in our environment.
Good example #2. SPA, NGINX, tar archives, Github releases
An environment is simple VPS. We have running NGINX server on this VPS, that is configured to search our project in the specific folder. Our SPA application is built and stored in the Github Releases as an attached file.
During the deployment, we’re downloading the tar archive from the corresponding Github Release and unarchive it to the right folder.
This example can be improved using symlinks, to make zero downtime deployment.
Bad example #1. SPA, Git, Circle Ci, Surge
The application is testing on Circle CI, and in case of successful passing the tests in develop branch, it is pushed to a staging environment.
Deploying of the production environment is done manually.
What to change?
We have to build artefact in CI and upload to the storage. Deployment has to use the actual build artefact from the storage. We don’t have to re-build the project during the deployment process.
Bad example #2. SPA, Git, NGINX
Simple web project. The deployment process includes this steps: engineer connects to the web server via ssh, pull the right commit, update the project’s dependencies, and run the build process.
What is wrong?
You can not be 100% sure in your build result. The built version is not tested. And even if it’s working locally, the version which was built on the remote server is made correctly.
What to change?
Review the build process. We need to separate build and release processes of the application. We have to store build artefact into the storage and use them during the deployment process.
If you split your release process into this stages, you will better understand the whole process. Each step has its own goal, its input and output artefacts.
Configure you release following these recipes and have smooth releases 😀