Anatomy of a ContinuousWorkflow with CI/CD

David
7 min readMar 24, 2023
Car assembly line
Photo by carlos aranda on Unsplash

This is the first part of two articles related to continuous workflows:

As developers, we focus on delivering code quickly and efficiently, avoiding conflicts the most.

When we are working on small personal projects or following tutorials it’s allowed to break things a little bit down and take risks using a single `main` branch to work on.

But when we are working on teams and our code base grows, managing code integrations is not easy, and we have to introduce some strategies that facilitate conflict resolutions (with code and people). Therefore, we should care about a continuous workflow in our “code factory” avoiding conflicts as much as possible.

Content

  • Our Code Mainline
  • Pipelines
  • Environments
  • Continuous Practices (CI/CD/Continuous Deployment)
  • Shared Responsibility and Adoption

Our Code Mainline

Before we dive into strategies there are a few things to know.

Imagine that you are not a software developer but instead, the chief in charge of a car manufacturer (yeah, each piece is code!) and we want to deliver cars as fast as we can.

As chiefs, we have to ensure that every piece is added correctly and doesn’t conflict with someone else work because if we do it wrong we could stop the mainline and lose a decent amount of time and money.

draw of a factory in which the employees are making pieces and adding them to a mainline

Let’s see what we have:

  • an assembly line
  • job spots
  • pieces
  • people
  • quality checks: car crash tests, velocity tests, etc.

Problem

If you noticed, one of the problems we got is that if a failure happens… we are only aware at the end, and probably we are going to need to redo the whole process again. This could be a total waste of time, so as chiefs, we have to introduce some strategies to prevent this to happen or at least reduce its impact in the mainline.

Solution

As we are producing the same car over and over, possible solutions would be:

  • synchronize and schedule integrations to the mainline, so we don’t assemble parts out of order. 🕥
  • make some tests in the job spots, so if something fails we know it upfront. ✅
  • have more pieces in the job spot to replace if some fail. 📦📦
  • automate some tasks so we may focus on the making, not on validation. 🤖
Enhanced process

We find the same problems when we are integrating our code base, but unlike our example, the code could be very different on each iteration because we expect different requirements in each cycle.

For that reason, synchronization and scheduling integrations are not good enough and we need additional tools:

Pipelines

To prevent failures and enhance software deliveries, and ensure everything is OK before we integrate our code to the mainline we decided to follow a series of steps to ensure everything is fine, these steps are called “the pipeline”.

recipe to prepare a meal
Photo by Rudy Issa on Unsplash

As a recipe, in a pipeline, we prepare the ingredients and follow instructions to deliver our code base, and if something goes wrong we undo and repeat the process with the learned lessons.

a pipeline is a series of steps that must be performed in order to deliver a new version of the software just before it’s integrated in the mainline

Let’s see what those steps are:

Building, code analysis, testing, containerizing, and deployment
  • In building, we produce the static files to be deployed (remember that when we are working locally we use ‘dev’ mode, and our code is not minified or optimized so they are not the same).
  • in code analysis, we could run a linter to evaluate the quality, security, and code conventions we use as a team
  • in testing, we run any kind of tests such as unit tests, integration tests, and so on (if you want to dig I wrote a testing article 😉);
  • containerizing is optional, just in case we need a containerized environment, so we ensure our code is going to work the same as on our machines;
  • in deployment, we move our static files to a place they can be delivered to the rest of the world (through S3 and CloudFront, for example).

Environments

Another tool we use to prevent errors is what we call environments to run different types of tests.

In general, there are working environments, testing environments, and production environments. We can refer to our work spots as our working environments, and the marketplace as our production environment.

an environment is nothing more than the place (hardware and software platform) where your app runs

speed test track
Photo by Sonnie Hiles on Unsplash

On the other hand, a testing environment is a place similar to our production environment where we run tests that simulate real-life scenarios, like a speed test track.

For the sake of clarity we can see different tests we run on different environments:

Different types of tests on each environment

note:

1 box is another practice used to validate our code in production environments, consists in releasing our product to a portion of users with a special taste so we can get their feedback or detect problems before it's fully available.

Now that we know the different tools it’s time to introduce the different processes we have depending on the level of our automation:

Continuous Practices

The main thing is to deliver code continuously and without conflicts as possible but how often is continuous?

As a rule of dumb, we call continuous when we deliver at least once a day.

Now let’s see some common practices:

Continuous Integration (CI)

It’s merging everybody’s work into a mainline with partially automated processes.

“Partially automated processes”, means that anything is automated except 2 stages: final tests and deployment process.

CI Workflow

On a normal day, team members integrate code through push/merge requests, then some automated tasks run such as static analysis, build, and some tests; finally, some manual work is done (pair reviews, regression tests, and deployment for example)

Continuous Delivery (CD)

It is an extension of Continuous Integration where all the steps are automated except the deployment process making the “when goes to market” a business decision.

Imagine that you (the developer) built a car, but business people have a kind of “red button” to decide when it goes on the market.

In Continuous Delivery we have the “red button” metaphor, everything is automated except the deployment to production

Notice that automatic tests are a little bit more highlighted in the draw because they are more robust in comparison with CI.

Piece of advice: it requires complete trust in our automation, specifically, our tests, therefore master CI so then try CD.

Continuous Deployment

It’s an extension of Continuous Delivery: every step is fully automated, and there is no red button to release to production, so every successful build results in a new deployment.

In Continuous Deployment everything is automated, indeed, pair reviews are omitted in some strategies

Piece of advice: Master CD before trying Continuous Deployment.

Share Responsibility and Adoption

In general, this is true:

team size and maturity, automation, and the delivery frequency grow from CI, to CD and finally to C Deploy

The shared responsibility between team members grows as automation grows, which means that any member of the team should be capable of doing tests, deploying, communicating, prioritizing, and accomplishing their tasks independently and effectively; for its part, automation grows as business requires to deliver value more often.

The business decides how often is going to deliver value

Although it may not seem like it, the most important thing for these changes and processes to be carried out is a change of mentality and interaction between stakeholders.

It requires maturity and therefore confidence in each member of the team, also business people need to get involved to understand the importance of splitting tasks into small chunks, good prioritization, and differentiation between:

  • Automatic error reports
  • User’s error reports
  • User’s suggestions
  • Business needs

Also, CI/CD workflows come hand in hand with the use of some additional processes such as agile methodologies, feature flags implementation, and a good branching strategy (go to the second part of this article “A Crash Course on Git Branching Strategies” 😄).

Summary

  • Our focus is to deliver code quickly and efficiently avoiding conflicts the most
  • A continuous workflow in the software world implies deployments at least once a day
  • A pipeline is a series of steps that must be performed to deliver a new version of the software
  • The CI is a semi-automated pipeline
  • The CD is a fully automated pipeline except for the deployment
  • Continuous Deployment is a fully automated pipeline
  • Deliver value is the main reason to do CI/CD.
  • CI/CD implementation requires a new mindset because it changes team interaction and processes
  • The shared responsibility between team members grows as automation grows

Additional Resources

--

--

David

Hi and welcome, I write about programming in an easy and friendly way so everyone get it