Express course · No. 20

Two ideas changed how software gets from a developer's laptop to real users. First, automate the whole path from code to production so releasing is boring instead of terrifying — that's CI/CD. Second, package the app with everything it needs so it runs identically everywhere — that's containers. Together they turn 'it works on my machine' from an excuse into the plan.

Essence only · One picture per idea · Learn the words

§ 01

Writing code is only half the job; getting it safely in front of users is the other half. For a long time that second half was slow, manual, and scary — and understanding why is the key to everything that fixes it.

Manual deploys are slow and scary

A surgeon performing a delicate operation by hand, from memory, at midnight, while tired — one slip and the patient is down. That's a manual production deploy.

The old way to ship was a human following steps by hand: copy files to a server, run some commands, cross your fingers. It's slow, error-prone, and so risky that teams deploy rarely — which makes each release huge, which makes it riskier still. A deploy is just "make the new version live," but done by hand it becomes the most stressful moment in the week. The whole field of CI/CD exists to make that moment boring.

The 'works on my machine' trap

A recipe that turns out perfectly in your kitchen and fails in someone else's — different oven, different flour, different altitude. The recipe wasn't the whole story.

Code that runs fine on a developer's laptop often breaks in production, because the two environments differ — different versions, settings, libraries, operating system. "It works on my machine" is the punchline for an entire class of bugs caused by these gaps. The deeper problem is that the laptop and the server aren't the same place, so "it worked where I built it" guarantees nothing about where it runs.

Releasing should be boring

An elevator you step into without a thought, a hundred times a day — because it's automated, tested, and safe. You'd never use one that needed a nervous manual procedure each trip.

The goal of everything in this course is to make shipping boring: so automated, tested, and repeatable that you release small changes many times a day without drama. Counter-intuitively, deploying more often is safer — each release is tiny, so if something breaks, the cause is obvious and the fix is small. Rare, giant, manual releases are the dangerous ones. Boring is the highest compliment a deploy can earn.

Manual deploys are slow, risky, and rare — which makes them riskier. The goal is the opposite: shipping so automated and small it's boring, done many times a day.

§ 02

The first half of CI/CD is about catching problems the instant they appear, by automatically building and testing every change as it lands — so the shared codebase always works.

Every change is built and tested automatically

A spell-checker that runs on every sentence as you type, flagging the mistake immediately — not a proofreader who finds a hundred errors a month later when it's all tangled together.

Continuous integration (CI) means that every time someone proposes a change, an automated system builds the project and runs the tests against it — within minutes, untouched by human hands. If the change breaks the build or fails a test, you know at once, while it's small and fresh in your mind. CI is an always-on guard that checks every contribution before it can cause trouble.

Catch breakage while it's small

Noticing a single brick laid crooked is easy to fix; discovering it only after building three floors on top is a disaster. Early is cheap; late is expensive.

The value of CI is timing. A bug caught the moment it's introduced is trivial to fix — you know exactly what changed. The same bug discovered weeks later, buried under everything built on top, can take days to untangle. By testing every change immediately, CI keeps problems tiny and traceable. It moves the discovery of breakage from "much later, mixed with everything" to "right now, in isolation."

Keep the main branch always working

A shared kitchen where everyone must clean up before leaving — so it's always usable for the next person, never a pile someone else has to sort out first.

CI's deeper purpose is keeping the main branch — the shared, trusted version — always in a working state. A change only joins main if it builds and passes the tests, so main never becomes a broken mess that blocks the whole team. This is what makes frequent, confident shipping possible: when main always works, you can release from it at any time without first untangling someone else's broken half-finished work.

Continuous integration builds and tests every change the moment it lands, catching breakage while it's small and keeping the main branch always in a working state.

§ 03

If CI makes sure every change is good, CD automates getting that good change out to users — turning release from a manual ritual into a button, or no button at all.

Automate the release, not just the testing

A factory line that doesn't stop at quality inspection but carries the approved product all the way to the loading dock and onto the truck — no one hand-carrying boxes.

Continuous delivery (CD) extends CI: after a change passes all the automated checks, the system also automatically prepares it for release and can push it to production. The manual, error-prone deploy steps become code that runs the same way every time. CI proves the change is good; CD gets that good change to users without a human carefully typing commands into a server at midnight.

Delivery versus deployment

A package sealed, addressed, and waiting by the door versus one already handed to the courier — both ready to go, but one waits for you to say the word.

There's a subtle split. Continuous delivery means every good change is automatically made ready to deploy, but a human presses the button to release it. Continuous deployment goes further: every change that passes is released to production automatically, no button at all. Both are "CD"; the difference is whether a person approves the final step. Teams choose based on how much they trust their automated checks.

The artifact is the thing you ship

A sealed, labelled box packed once and then shipped, stored, and delivered as a single unit — not re-assembled from loose parts at each stop.

The pipeline produces an artifact — a single, built, versioned package of your application, ready to run. You build it once and that exact same artifact moves through testing, staging, and production, so what you tested is precisely what you ship. This is key to reliability: if you rebuilt at every stage, subtle differences could creep in. One artifact, built once, deployed everywhere, removes a whole class of "but it passed in testing" surprises.

Continuous delivery automates the release of every good change as a single built artifact — whether a human presses the final button (delivery) or it ships itself (deployment).

§ 04

CI and CD are run by a pipeline: an automated assembly line a change travels through, from commit to production, stopping if anything goes wrong along the way.

A pipeline is an automated assembly line

A car factory line: the chassis moves through welding, painting, and inspection in order, each station doing its job before passing it on — no step skipped, no manual carrying.

A pipeline is the sequence of automated stages a change passes through on its way to production — typically build, then test, then deploy. A commit enters one end and, if all is well, a live release comes out the other, with no human steps in between. The pipeline is the concrete machine that makes CI/CD real: it's where "automate the whole path" actually lives, as defined, repeatable stages.

Fail fast: stop the line on a problem

An assembly line with a cord anyone can pull to halt everything the instant a defect appears — far better than letting flawed products roll all the way to shipping.

A good pipeline is built to fail fast: if the build breaks or a test fails at any stage, the pipeline stops and the change goes no further. A broken change never reaches production because the line halts the moment it's caught. This is the safety property of the whole setup — every change must pass through every gate, and a single red light stops the release cold. Nothing flawed slips through to users.

Green means go, red means stop

A traffic light on the line: green and the work flows on; red and everything waits until the problem is cleared. No judgment calls, just a clear signal.

Pipelines speak in green (passed) and red (failed). A green pipeline means every check passed and the change is safe to proceed; a red one means something broke and must be fixed before anything moves. This simple signal replaces anxious manual judgment with an unambiguous gate. The team's rule becomes easy: never build on red, never ship on red — keep the pipeline green and shipping stays safe by default.

The pipeline is the automated assembly line from commit to production — build, test, deploy — that fails fast and stops on red, so no broken change slips through.

§ 05

The other half of the story solves "works on my machine" directly: package the app with everything it needs into one unit that runs identically everywhere. That unit is a container.

A container packages the app with everything it needs

An astronaut's suit carrying its own air, temperature, and pressure — so the person works the same whether on the station or in open space, bringing their environment with them.

A container bundles your application together with everything it needs to run — the code, the libraries, the settings, the right versions — into one self-contained unit. Because it carries its own environment, it runs the same way wherever you put it: your laptop, a test server, production. The container doesn't depend on what's installed on the host, so the gaps that cause "works on my machine" simply close.

The shipping container that named it

The steel shipping container: any port, ship, or truck handles it the same way because the box is standard, no matter what's inside. The world's cargo moves on that one idea.

The name is the metaphor. Before standard shipping containers, cargo was loaded piece by awkward piece; the standard box let any crane and any ship handle any cargo identically. Software containers do the same for applications: a standard unit that any compatible system can run without caring what's inside. Docker is the tool that made this mainstream. Standardising the box is what makes the whole logistics chain — your pipeline — work smoothly.

Image versus container: recipe and dish

A recipe versus the meal cooked from it: one is the fixed set of instructions, the other is a specific instance you can make many of, all identical.

Two words get mixed up. An image is the packaged, frozen blueprint — the built artifact containing your app and its environment, sitting in storage. A container is a running instance started from that image. One image can launch many identical containers, the way one recipe makes many identical dishes. You build the image once in your pipeline, then run as many containers from it as you need — and every one is the same.

A container packages an app with everything it needs, so it runs the same everywhere. You build an image once (the recipe) and run identical containers from it (the dish).

§ 06

Running one container is easy. Running hundreds across many machines — keeping them healthy, scaling them, updating them without downtime — needs a conductor. That's orchestration.

Orchestration runs many containers across many machines

An air traffic controller managing a sky full of planes — deciding which lands where, rerouting around problems, keeping hundreds of moving parts safe and coordinated.

Once you have many containers spread over a fleet of servers, something must decide where each one runs, restart the ones that die, and balance the load. That's orchestration, and the dominant tool is Kubernetes. You tell it the desired state — "run five copies of this service" — and it continuously works to make reality match, placing containers, watching them, and fixing drift. It's the conductor coordinating the whole orchestra of containers.

Self-healing and scaling come built in

A thermostat you set to a target temperature: it constantly senses the room and adjusts on its own, without you touching it again. You declare the goal; it maintains it.

Orchestration is declarative: you describe the goal, not the steps. Say "always keep five healthy copies running," and if one crashes, the system starts a replacement automatically — self-healing. If traffic spikes, it can add more copies and remove them when demand falls — auto-scaling. You stop manually nursing servers and instead declare what you want, letting the orchestrator hold the system there. That shift from doing to declaring is the heart of it.

Rolling updates ship without downtime

Replacing the tires on a moving truck one at a time, so it never has to stop — the vehicle keeps rolling while each part is swapped underneath it.

Orchestration lets you update with no downtime through a rolling update: it replaces old containers with new ones a few at a time, checking each is healthy before continuing, so the service stays up throughout. If a new version misbehaves, it can stop and roll back to the old one automatically. This is how modern services ship updates continuously without a maintenance window — the swap happens live, gradually, and reversibly.

Orchestration (Kubernetes) runs many containers across many machines: you declare the desired state, and it self-heals, auto-scales, and rolls out updates without downtime.

§ 07

All this machinery exists to make shipping safe and frequent. The final habits are about reducing the blast radius of any one release — because the safest deploy is one you can undo.

Always have a way back: rollback

A document with undo: you make a bold change knowing one keystroke restores the previous version, so you experiment freely instead of fearing every edit.

The most important safety property is the rollback — the ability to return instantly to the last known-good version when a release goes wrong. Because the pipeline ships versioned artifacts, going back is just redeploying the previous one. Knowing you can undo a deploy in seconds is what makes frequent releasing safe: a bad version is a minor, reversible blip rather than a crisis. Never ship something you can't take back.

Reduce the blast radius: canary and blue-green

Tasting a new dish on a few willing guests before serving it to the whole banquet — if it's off, only a few notice, and you've lost nothing.

Two patterns shrink the risk of a release. A canary deploy sends the new version to a small slice of users first; if their metrics stay healthy, you roll it out to everyone, and if not, you pull it back having affected almost no one. Blue-green keeps two production environments and switches traffic from the old (blue) to the new (green) all at once, with an instant switch back if needed. Both turn a release from an all-or-nothing gamble into a controlled, reversible step.

Describe your infrastructure as code

A blueprint you can rebuild the whole house from exactly, versus a house built from memory that no one can reproduce if it burns down.

The same discipline extends to the servers themselves. Infrastructure as code (IaC) means defining your servers, networks, and configuration in files instead of clicking through a console by hand. Now your whole environment is versioned, reviewable, and reproducible — you can rebuild it identically, and changes go through the same pipeline as code. It closes the last gap where "someone changed a setting by hand and forgot" could undo all the rigor everywhere else.

Before you rely on a deploy process
  • Is it automated end to end — commit to production through a pipeline, not by hand? - Does CI build and test every change, keeping main always working? - Is what you ship a single artifact or container, identical from test to prod? - Can you roll back instantly to the last good version? - Do risky releases go out gradually — canary or blue-green, not all at once? - Is the infrastructure itself code — versioned and reproducible?
The words you now own
  • deploy / release — making a new version live for users. - CI (continuous integration) — auto-build and test every change. - CD (continuous delivery / deployment) — automate the release; button, or no button. - pipeline / build / artifact / fail fast — the automated line, its output, and its safety. - container / image / Docker — the app with its environment, the blueprint, the tool. - orchestration / Kubernetes / self-healing / rolling update — running containers at scale, safely. - rollback / canary / blue-green / infrastructure as code — the patterns of a safe deploy.
Signs you ship well
  • Releasing is boring — small, automated, and done often, not a rare scary event. - CI is green before anything merges, and main always works. - You ship the same artifact/container you tested, all the way to production. - A bad release is a quick rollback, not a crisis. - Risky changes go out by canary or blue-green, and your infra is code.

Safe shipping is reversible shipping: automate the pipeline, ship one tested artifact, keep a one-click rollback, release risky changes gradually, and define infrastructure as code.

End of express course · 7 chapters · learn the words

Next comes practice: take a small project, write a Dockerfile so it runs in a container, and set up a pipeline that builds and tests it on every change. Then deploy it, break it, and roll back. The whole philosophy clicks the moment a release stops feeling scary because you know the line caught it and you can undo it. But hold one idea above the rest: shipping should be boring. Automate the path so every change is built, tested, and deployable the same way, and package the app so it runs identically everywhere — and "it works on my machine" finally becomes "it works everywhere."