There is a huge difference between developing a small web application by yourself and being part of a big team of developers, managers, marketing people, and so on, that works around the same big web application. Working on an application used by thousands or millions of users has a clear risk: if you mess it up, there will be a huge number of unhappy affected users, which may translate into sales going down, partnerships terminated, and so on.
From this scenario, you can imagine that people would be scared when they have to change anything in production. Before doing so, they will make sure that everything works perfectly fine. For this reason, there is always a heavy process around all the changes affecting a web application in production, including loads of tests of all kinds.
Some think that by reducing the number of times they deploy to production, they can reduce the risk of failure, which ends up with them having releases every several months with an uncountable number of changes.
Now, imagine releasing the result of two or three months of code changes at once and something mysteriously fails in production: do you know where to even start looking for the cause of the problem? What if your team is good enough to make perfect releases, but the end result is not what the market needs? You might end up wasting months of work!
Even though there are different approaches and not all companies use them, let's try to describe one of the most famous ones from the last few years: continuous integration (CI). The idea is to integrate small pieces of work often rather than big ones every once in a while. Of course, releasing is still a constraint in your system, which means that it takes a lot of time and resources. CI tries to automatize this process as much as possible, reducing the amount of time and resources that you need to invest. There are huge benefits with this approach, which are as follows:
- Releases do not take forever to be done, and there isn't an entire team focused on releasing as this is done automatically.
- You can release changes one by one as they come. If something fails, you know exactly what the change was and where to start looking for the error. You can even revert the changes easily if you need to.
- As you release so often, you can get quick feedback from everyone. You will be able to change your plans in time if you need to instead of waiting for months to get any feedback and wasting all the effort you put on this release.
The idea seems perfect, but how do we implement it? First, let's focus on the manual part of the process: developing the features using a version control system (VCS). The following diagram shows a very common approach:

As we already mentioned, a VCS allows developers to work on the same codebase, tracking all the changes that everyone makes and helping on the resolution of conflicts. A VCS usually allows you to have different branches; that is, you can diverge from the main line of development and continue to do work without messing with it. The previous graph shows you how to use branches to write new features and can be explained as follows:
- A: A team needs to start working on feature A. They create a new branch from the master, in which they will add all the changes for this feature.
- B: A different team also needs to start working on a feature. They create a new branch from master, same as before. At this point, they are not aware of what the first team is doing as they do it on their own branch.
- C: The second team finishes their job. No one else changed master, so they can merge their changes straight away. At this point, the CI process will start the release process.
- D: The first team finishes the feature. In order to merge it to master, they need to first rebase their branch with the new changes of master and solve any conflicts that might take place. The older the branch is the more chances of getting conflicts you will have, so you can imagine that smaller and faster features are preferred.
Now, let's take a look at how the automated side of the process looks. The following graph shows you all the steps from the merging into master to production deployment:

Until you merge your code into master, you are in the development environment. The CI tool will listen to all the changes on the master branch of your project, and for each of them, it will trigger a job. This job will take care of building the project if necessary and then run all the tests. If there is any error or test failure, it will let everyone now, and the team that triggered this job should take care of fixing it. The master branch is considered unstable at this point.
If all tests pass, the CI tool will deploy your code into staging. Staging is an environment that emulates production as much as possible; that is, it has the same server configuration, database structure, and so on. Once the application is here, you can run all the tests that you need until you are confident to continue the deployment to production. As you make small changes, you do not need to manually test absolutely everything. Instead, you can test your changes and the main use cases of your application.