

# How fully CI/CD processes are different
<a name="fully-cicd-process-differences"></a>

CI/CD pipelines use a modern *trunk-based workflow*, in which developers merge small, frequent updates into a main branch (or *trunk*) that is built and tested through the CD portion of the CI/CD pipeline. This workflow has replaced the *Gitflow workflow*, in which development and release branches are separated by a release schedule. In many organizations, Gitflow is still a popular method of version control and deployment. However, it is now considered legacy, and it can be challenging to integrate into a CI/CD pipeline.

For many organizations, the transition from a Gitflow workflow to a trunk-based workflow has been incomplete, and the result is that they get stuck somewhere along the way and never fully migrate to CI/CD. Somehow, their pipelines end up clinging to certain remnants of the legacy workflow, stuck in a transitional state between past and present. Review the differences in the Git workflows, and then learn how using a legacy workflow can affect the following:
+ [Environment integrity](environment-integrity.md)
+ [Releases](releases.md)
+ [Security](security.md)

To make it easier to identify the remnants of a legacy Git workflow in a modern configuration, let's compare [Gitflow](#gitflow-approach) to the modern, [trunk-based](#trunk-based-approach) approach.

## Gitflow approach
<a name="gitflow-approach"></a>

The following image shows a Gitflow workflow. The Gitflow approach uses multiple branches to track several different versions of the code at the same time. You schedule releases of updates to an application for some point in the future while developers still work on the current version of the code. Trunk-based repositories can use feature flags to accomplish this, but it's built in to Gitflow by default.



![\[A Gitflow workflow with feature, development, release, and hotfix branches\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/strategy-cicd-litmus/images/gitflow-workflow.png)


One result of the Gitflow approach is that the application environments are usually out of sync. In a standard Gitflow implementation, development environments reflect the current state of the code while the preproduction and production environments remain frozen on the state of the code base from the most recent release.

This complicates things when a defect appears in the production environment because the code base that the developers work in cannot be merged into production without exposing unreleased features. The way Gitflow handles this situation is by using a hotfix. A hotfix branch is created from the release branch and then deployed straight into the upper environments. The hotfix branch is then merged into the development branch in order to keep the code current.

## Trunk-based approach
<a name="trunk-based-approach"></a>

The following image shows a trunk-based workflow. In a trunk-based workflow, developers build and test features locally in a feature branch and then merge those changes into the main branch. The main branch is then built to the development, preproduction, and production environments, sequentially. Unit and integration tests occur between each environment.



![\[A trunk-based workflow with feature branches and a main branch.\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/strategy-cicd-litmus/images/trunk-based-workflow.png)


Using this workflow, all environments are operating the same code base. There is no need for a hotfix branch for the upper environments because you can implement changes in the main branch without exposing unreleased features. The main branch is always assumed to be stable, free of defects, and ready to release. This helps you integrate it as a source for a CI/CD pipeline, which can automatically test and deploy your code base through all environments in your pipeline.

# Environment integrity benefits of a trunk-based approach
<a name="environment-integrity"></a>

As many developers know, one change in code can sometimes create a [butterfly effect](https://www.americanscientist.org/article/understanding-the-butterfly-effect) (American Scientist article), where a small deviation that is seemingly unrelated sets off a chain reaction that causes unexpected results. Developers must then fully investigate to discover the root cause.

When scientists conduct an experiment, they separate the test subjects into two groups: the experimental group and the control group. The intention is to make the experimental group and the control group completely identical except for the thing being tested in the experiment. When something happens in the experimental group that doesn't happen in the control group, the only cause can be the thing being tested.

Think of the changes in a deployment as the experimental group, and think of each environment as separate control groups. The results of testing in a lower environment are only reliable when the controls are the same as in an upper environment. The more the environments deviate, the greater the chance of discovering defects in the upper environments. In other words, if the code changes are going to fail in production, we'd much rather them fail in beta first so that they never get to production. This is why every effort should be made to keep each environment, from the lowest test environment to production itself, in sync. This is called *environment integrity*.

The goal of any fully CI/CD process is to discover issues as early as possible. Preserving the environment integrity by using a trunk-based approach can virtually eliminate the need for hotfixes. In a trunk-based workflow, it's rare for an issue to first appear in the production environment.

In a Gitflow approach, after a hotfix is deployed directly to upper environments, it is then added to the development branch. This preserves the fix for future releases. However, the hotfix was developed and tested directly off of the current state of the application. Even if the hotfix works perfectly in production, there's a possibility that problems will arise when it interacts with the newer features in the development branch. Because deploying a hotfix for a hotfix is not typically desirable, this leads to developers spending extra time trying to retrofit the hotfix into the development environment. In many cases, this can lead to significant technical debt and reduce the overall stability of the development environment.

When a failure occurs in an environment, all changes are rolled back so that the environment is returned to its previous state. Any change to a code base should start the pipeline over again from the very first stage. When an issue does arise in the production environment, the fix should go through the entire pipeline as well. The extra time it takes to go through the lower environments is usually negligible compared to the problems that are avoided by using this approach. Because the whole purpose of the lower environments is to catch mistakes before they reach production, bypassing these environments through a Gitflow approach is an inefficient and unnecessary risk.

# Release benefits of a trunk-based approach
<a name="releases"></a>

One of the things that often makes a hotfix necessary is that, in a legacy workflow, the state of the application that developers are working on might contain several unreleased features that are not yet live in production. The production environment and the development environment only become in sync when a scheduled release occurs, and then they immediately begin to diverge again until the next scheduled release.

Having scheduled releases is possible within a fully CI/CD process. You can delay the release of code to production by using feature flags. However, a fully CI/CD process allows more flexibility by making scheduled releases unnecessary. After all, *continuous* is a key word in CI/CD, and that suggests that changes are released as they become ready. Avoid maintaining a separate release environment that is almost always out of sync with the lower test environments.

If a pipeline is not fully CI/CD, the divergence between upper and lower environments usually occurs at the branch level. Developers work in a development branch and maintain a separate release branch that is updated only when it is time for a scheduled release. As the release branch and the development branch diverge, other complications can arise.

In addition to environments being out of sync, as developers work on the development branch and become accustomed to an application state that is far ahead of what is in production, they must readjust to the state of production every time an issue arises there. The state of the development branch could be many features ahead of production. When developers work in that branch every day, it's difficult to remember what is and isn't released to production. This adds risk that new bugs will be introduced while in the process of fixing other bugs. This result is a seemingly endless cycle of fixes that extend timelines and delay feature releases for weeks, months, or even years.

# Security benefits of a trunk-based approach
<a name="security"></a>

A fully CI/CD process provides a fully automated single source of truth approach to deployment. The pipeline has a single point of entry. Software updates enter the pipeline at the beginning and are passed as-is from one environment to the next. If an issue is discovered at any stage in the pipeline, the code changes that fix it must go through the same process and start at the first stage. Reducing the points of entry in a pipeline also reduces the possible ways that vulnerabilities can be introduced into the pipeline.

Additionally, because the entry point is the furthest possible point from the production environment, this drastically reduces the likelihood of vulnerabilities reaching production. If you implement a manual approval process in a fully CI/CD pipeline, you can still allow for go or no-go decision making about whether changes are promoted to the next environment. The decision maker is not necessarily the same person who deploys changes. This separates the responsibilities for the deployer of code changes and the approver of those changes. It also makes it more feasible for a less technical organization leader to perform the role of approver.

Finally, the single point of entry helps you limit write access to the production environment's user interface (UI) console to a few or even zero users. By reducing the number of users who can make manual changes in the console, you reduce the risk of security events. The ability to manually manage the console in the production environment is far more necessary in legacy workflows than in a CI/CD automated approach. These manual changes are more difficult to track, review, and test. They're usually performed to save time, but in the long run, they add significant technical debt to the project.

Console security issues aren't necessarily caused by bad actors. Many of the issues that occur in the console are accidental. Accidental security exposure is very common, and it has led to the rise of the zero-trust security model. This model posits, in part, that security accidents are less likely when even internal staff has as little access as possible, also known as *least-privilege permissions*. Preserving the integrity of the production environment by restricting all processes to an automated pipeline practically eliminates the risk of console-related security issues.