The Details: CI
CI is how developers test and verify their code is ready to go.
Last updated: March 3, 2025
Let's dive deeper into CI . We’re going to look at what types of tests developers run in CI, how they integrate with version control systems, and where teams set up CI (on your own server, or in the cloud ).
Refresher: What is CI?
Continuous Integration and Continuous Delivery (big words) are all about getting new code out into the wild as quickly and as securely as possible. CI is about the secure part – making sure that code is well tested and is going to perform on the stage exactly how you expect it to (or at least as close as we can get it).
Back in the day – especially before cloud delivered software became the norm – software upgrades were infrequent, difficult, and risky. It was hard to know if the new feature you built might cause something to break incidentally, and logistically, getting that new feature out to your users required some degree of coordination. Because of that, companies would batch new features and bug fixes together into big new releases.
As we started moving software to the cloud though, that all changed – upgrades started happening automatically and without notification. For example, when you’re using Gmail in your web browser, you’ll notice that Google is constantly changing and improving it, from how it looks to how you navigate around and even behind the scenes performance changes. You don’t click “update,” the stuff just continuously (see?) shows up.
🚨 Confusion Alert
Plenty of software still follows more traditional update models. For example, when you want to update iOS on your phone or MacOS on your laptop, you need to actively choose to download and apply the update. Plus, Apple bundles new features and bug fixes together. The same is true for updating the apps on your phone. For cloud software though – especially B2B – the standard is becoming this permissionless update cycle.
This shift was powerful for software companies – it let them iterate extremely quickly on the product, get new features out into the wild near instantaneously, and gather product feedback through experimentation.
What enables this lightning quick delivery is a new approach to testing and deploying software, or what you’ve been hearing about with this CI/CD stuff. In a nutshell:
-
CI is the process of extensively testing every new unit of code you want to deploy, automatically and quickly
-
CD is the process of getting your new, now-tested in the hands of your users automatically and quickly
Another way of thinking about CI/CD is as a process of automation: the manual testing and deployment that used to take so much engineer time is now making its way into code and SaaS. In this post, we’re going to dive deeper into both CI and CD, what they entail, and what engineering teams use to do them.
This post is going to go deeper into the CI part; but keep in mind that the two are intertwined.
Types of tests: what CI is running
An engineer’s nightmare: after working on an exciting new feature for a week and quickly getting it out to users, bug reports start to roll in. It turns out the new feature broke an existing workflow and it’s causing users to lose data (😨). For anyone who has worked at a startup, you already know how common this is; CI is aimed at fixing this exact problem.
As engineering teams and codebases mature, they add in more and more tests to make sure that things will work as expected. That way, you can catch these errors before they hit your users. Of course, you’ll never be able to catch everything – bugs are a fundamental reality of software, whether we like it or not. But tests can help.
So what exactly are these tests we’re talking about? A few examples:
Unit tests
Unit tests are the broadest category, and refer to tests that check that a unit of code is doing what it’s expected to. A unit test can be something as small as verifying that a function returns an intended data type, or as large as verifying the structure of an object generated from a set of functions. The philosophy behind them is ensuring that each logical unit of code produces exactly what you expect it to, and that keeping these tests low level makes it easier to understand what went wrong if the whole thing doesn’t work.
Linting and code rules
These are tests that check code formatting and style. Developers want to maintain consistency across the codebase, and linters help enforce stylistic rules. Some common examples of linting rules are not allowing trailing spaces, setting a maximum number of characters per line of code, and removing any unused library imports at the top of files. Open source packages like ESLint for JavaScript allow engineers to set codebase-wide linting rules that you can enforce in CI.