I’m sure you searched it and discovered that CI means Continuous Integration and CD, Continuous Delivery or Deployment, but what does it actually mean?
Do you have a smart speaker, like a Google mini or an Amazon echo? Have you created routines with them? If not, let’s walk you through this concept.
Smart speakers have voice recognition skills and can perform tasks when triggered by a voice command. You can just say ‘Speaker, play some music’: the speaker will hear the ‘trigger’ being its own name: ‘speaker’ in this above example, ‘Alexa’ for an Amazon echo, ‘Okay Google’ for the Google ones. It will then start listening to the commands following the trigger and perform a task, as long as the command is recognised.
Routines for a smart speaker are personalised actions or a list of actions that the speaker will perform after a personalised trigger. Let’s say that I do the same things every night when I go to sleep: I turn off the TV, I dim the lights in my bedroom, I play some relaxing music at a low volume, I silence my phone… I could create a ‘routine’ where I say ‘speaker, goodnight’ and all the above tasks are done automatically. The smart speaker would reach out to the TV to turn it off, dim the bedroom light, play some relaxing music and adjust the volume, silence my phone…
(This example would require a few upgrades to the house to connect lights, TV etc to the Wi-Fi, but you got the concept.)
It’s good to note that smart speakers’ routines can be triggered by a voice command, another action (i.e. ‘when my phone connects to the Wi-Fi’) or scheduled (i.e. ‘every day at 3pm’).
A pipeline is the same concept as a routine: a list of actions performed automatically after a trigger.
The CI pipeline (Continuous Integration) helps developers continuously test their code, “integrating” it to the application. It answers the questions “Does my new code work?” and “Does it break anything?”.
Imagine that we have a CI routine in our smart speaker: a list of actions that tests every smart device we have in the house. The CI routine will turn on and off every light, device, thermostat, lock and unlock the door, play and stop the music, turn up and down the volume… It would basically just try out every task on every smart device we have and finish with a voice confirmation “All in working conditions”.
Now, let’s add a piece of code to our application: let’s buy a new smart device; a lamp for my office.
When I plug it in, I want the CI routine to run the tests and confirm that it’s ‘All in working conditions’ so I would know I didn’t break anything.
However, imagine that, to plug the lamp in, I had to unplug the TV. The CI routine would fail with ‘TV not found’, so I would realise that my new code broke some existing one.
When I have a new piece of code, a new feature, I might want to add unit tests for it; or in TDD (Test Driven Development) I usually create tests before I create the new feature. In this case I add tests for the lamp to the CI routine and I make the smart speaker turn it on and off. Now the CI routine can run again and, apart from not having broken anything else already existing in the house, I also know the lamp works fine.
In a TDD scenario I would’ve added tests for the lamp to the CI routine before physically connecting it to the electricity and ran the CI routine for it to tell me ‘lamp not found’. This way I would know the tests are proper and they actually look for the lamp, rather than succeeding because I configured them incorrectly, which would trick me into thinking my lamp is working, when it’s not. I would then connect the lamp, run the CI routine again and see it succeeding.
A CD pipeline (Continuous Delivery or Deployment) is a little more complex to adapt to a smart speaker example, so let’s take a step back to create some context.
In software development, we have the concept of environments, which range from local to production, via development and test, and can be explained as copies of our smart house, where we experiment with our new devices, so that we don’t break the actual production house we’re using and living in. Obviously, this concept doesn’t really make sense in real life, but stay with me.
Imagine that the house we’re adding all these smart devices in, is not ours. We’re just some personal assistant for a rich family.
Local environment is where we work and implement new code i.e. a factory where we create new devices.
Development is where we first test them out and where a CI pipeline usually runs i.e. a copy of the rich family’s house that keeps getting experimented in, where a copy of all the devices are connected together and tested.
Test environment can be multiple ones and have various names depending on specific purpose. This is a functioning, very similar copy of the rich family’s house, where we triple check the setup before we deliver it. Imagine that there are many assistants and we are all experimenting new devices in the development house. Maybe my new device works well in the development house because another assistant made a change, while experimenting, that allowed my device to work. Now, he didn’t proceed with his change, but I did. In the test house, I’m going to have a last chance to notice it failing before it’s delivered to our clients.
Sometimes the test environment already serves this purpose, but sometimes you’ll find yourself in front of a staging or pre-production environment, which is an extra step to catch ‘bugs’ and make ‘hot fixes’. This can be a house we fake living in ourselves and we use the new devices in, exactly in the same way as we want our clients to. We don’t only want to confirm they work, but also try the customer’s experience and other much deeper testing scenarios to fully confirm that, once we go to production, we won’t have problems.
Production: where our product goes public and customers can use it: the rich family’s house. Don’t forget to ‘monitor’ your production environment to make sure it’s continuously working well: get live data from the devices in production and set alarms to let you know when something is not working properly i.e. TV took over 5 seconds to turn on.
Now back to our CD pipelines.
First of all, in a new feature implementation lifecycle, a CD pipeline runs after a CI pipeline and goes a step further with our new code: after the CI checks if it integrates well and succeeds, the CD will actually deliver it to our higher environments.
Continuous Delivery and Continuous Deployment are also slightly different concepts. Let’s see below how they differ:
After the CI routine runs successfully in the development house, we want the CD pipeline to deliver the lamp to the test house so we can continue with our testing.
Afterwards, the Continuous Delivery pipeline will wait for us to manually trigger or manually approve deployments to production, i.e. actually adding the lamp to the rich family’s house, only when I am fully convinced I want to do so. It will therefore leave us some human control over the final steps of deployment to production, to perhaps be able to abort or postpone, if we decide to do so.
Deployments from testing environment and all the way to production via a Continuous Delivery pipeline are usually grouped in ‘releases’: a branch of our repository with a number of new features that are tested together, in order to deal with fewer but bigger deployments i.e. my new lamp, a new TV and a new door lock are all scheduled to be delivered on the same ‘release day’.
A Continuous Deployment pipeline instead, would leave us zero manual tasks to do, once our new device has been tested and works. However, this would also give us less control over confirming that we want to deploy it to production i.e. it would directly add the lamp to the rich family’s house, once all checks in test and pre-production pass.
It would, this way, scrap the idea of a ‘release day’ (deployment to production day), to automatically continuously deploy every change that passes the tests in testing and pre-production, all the way to production.
Last but not least, all pipelines need some ‘triggers’.
As noted, our smart speaker routines could run when we say so, when we do something, or scheduled. Pipelines can have these similar triggers: we can have a manual trigger; an event trigger i.e. run the CI when I push a commit to my remote repo (NB most popular); or a scheduled trigger i.e. run everyday at 6pm.
Got it?
Now you can go read some technical stuff about CI/CD pipelines and it should all make more sense.
Don’t hesitate to get in touch with me via LinkedIn at /debora-piu.