01/13Laptop → users

LEARN TO PROGRAM · CHAPTER 16 · ARCHITECTURE

Shipping it

Code on your laptop helps nobody. Shipping is everything between "it works on my machine" and "it works for everyone, and we'll know if it stops": saving versions, checking each other's work, building, testing, packaging, deploying carefully, and watching it run.

The 3D is one long conveyor. Follow a change along it, station by station. Each station is a program you can run here, from a git-style hash to the rule that decides whether to wake someone at 3 a.m.

Every code block runs in your browser. Edit it, break it, press Run.

01 · LAPTOP → USERS

The path of a commit

A change is born on the back-left of the floor and ends up in the city at the front. On its way it is committed to version control, reviewed by a colleague, built into files a machine can run, tested by robots, packaged into a container, deployed to a small slice of users and then to everyone, and watched. The crates change shape as they go: a commit, a bundle, a container.

Every arrow on that path is automated in a healthy team. A person decides what to change and whether a change is good; machines do the rest, the same way every time. That is what lets big teams ship many times a day without breaking things.

journey.js

The minutes are made up, but the shape is typical: the human step (review) is usually the slowest. Change the numbers for your own team.

5 metricsthat the DORA research programme uses to measure software delivery: change lead time, deployment frequency, failed deployment recovery time, change fail rate and deployment rework rate. Speed and stability, measured together. DORA

02 · VERSION CONTROL

Version control: a history you can trust

Version control records every saved state of a project, who made it and why, so you can go back, compare, and work in parallel without overwriting each other. Today that almost always means git. A commit is a snapshot of all your files plus a message and a pointer to the commit before it, its parent.

The trick that makes git trustworthy is that a commit's name is a hash of its content, parent included. Here is the idea in a few lines, with a small hash function standing in for git's (git uses SHA-1, hardened against known attacks, and is moving to SHA-256):

commits.js

Change "hello" in the first commit and run again: all three ids change. The ids on the 3D graph are the ones this prints.

Branches, merges, rebases, checking out the past: the Git Time Machine lets you do all of it to a real commit graph in 3D, so this chapter won't repeat it. Spend ten minutes there, then come back.

03 · BRANCHES & REVIEW

Branches and code review

Nobody commits straight to main on a team. You make a branch, commit your work there, and open a pull request (or merge request): a proposal to merge your branch, shown as a diff, the lines removed in red and added in green. Teammates read it, comment, and approve. Then it merges.

A diff is itself an algorithm: find the longest run of lines the two versions share, and everything else is a removal or an addition. Git's default is Eugene Myers' 1986 algorithm; this is the simpler textbook version, built on the longest common subsequence:

diff.js

The output is the panel in the 3D. Press Step through and watch i and j walk the two files.

Why review at all? Finding bugs is the reason people give, but a study of review at Microsoft (Bacchelli and Bird, 2013) found reviews are less about defects than developers expect, and bring other benefits: shared knowledge, awareness of what the team is changing, and better alternative solutions. At Google review is mandatory; its 2018 study of the practice drew on logs of 9 million reviewed changes.

04 · BUILDS & BUNDLING

Builds and bundling

The code you write isn't what runs. A build turns source into something you can ship: TypeScript becomes JavaScript, C becomes a binary, many small files become a few big ones. For the web, a bundler follows every import from an entry file, puts each module after the modules it depends on, drops code nothing uses (tree-shaking), shrinks it (minifying), and names the output after a hash of its contents.

bundler.js

The 3D build machine eats the files in this order, and drops unused.js in the bin. Edit any file's code and the output name changes.

That hashed name matters. Browsers can cache app.64fe6c11.js forever, because a new version gets a new name. And a good build is reproducible: the same source and the same lockfile (the exact version of every dependency) give the same output, on your laptop and on the build server.

terminal
npm ci          # install exactly what package-lock.json says
npm run build   # here: tsc, then a bundler such as esbuild or Vite

05 · CI/CD

CI/CD: robots that check every change

Continuous integration (CI) means everyone merges small changes into the main line often, and every change is built and tested automatically. Kent Beck developed it as part of Extreme Programming in the 1990s; Martin Fowler's 2000 article made it famous. Continuous delivery (CD) goes further: every change that passes is ready to release. Continuous deployment releases it automatically.

A pipeline is a list of stages, and any failure stops the line, so a broken change never reaches users. On the stage, one crate in five fails its tests and is pushed into the reject bin. So does this program, on purpose:

pipeline.js

One test fails. Fix slugify (hint: strip a leading or trailing - with another .replace) and the pipeline runs to deploy.

In real life the pipeline is a file in your repository, run by a service such as GitHub Actions or GitLab CI on a fresh machine for every push:

.github/workflows/ci.yml
# .github/workflows/ci.yml · runs on every push and pull request
name: ci
on: [push, pull_request]
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7      # get the commit
      - uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: npm                   # reuse downloads between runs
      - run: npm ci                    # exact versions from the lockfile
      - run: npm run lint
      - run: npm test
      - run: npm run build

To drive a full pipeline (build, test, scan, canary) and watch it catch a bad commit, open The Pipeline.

06 · CONTAINERS

Containers and Docker

"It works on my machine" happens because machines differ: a different Node version, a missing library, another operating system. A container image packs your program together with everything it needs: the files of a small Linux system, the runtime, your dependencies and your code. Run it anywhere and you get the same thing.

A container is not a virtual machine. It is an ordinary process that the Linux kernel fences off: namespaces give it its own view of files, processes and network, and cgroups cap the CPU and memory it can use. It shares the host's kernel, so it starts in moments.

Dockerfile
# Dockerfile · each instruction is a layer
FROM node:24-slim                 # a small Linux with Node installed
WORKDIR /app
COPY package*.json ./             # copy only the dependency list first...
RUN npm ci                        # ...so this slow step stays cached
COPY . .                          # then the code, which changes often
RUN npm run build
USER node                         # don't run as root
EXPOSE 3000
CMD ["node", "dist/server.js"]

Every instruction makes a layer, and layers are cached. A layer's cache key covers its instruction, the files it reads and everything below it, so when one layer changes, every layer above it is rebuilt. This simulation prints what the 3D container shows:

layer-cache.js

The slow npm ci stays CACHED because the dependency list didn't change. Practice exercise 3 shows what happens when you get the order wrong.

71.1%of developers in the 2025 Stack Overflow survey use Docker, up 17 points in a year: the largest jump of any technology surveyed. Stack Overflow Developer Survey 2025

The finished image is pushed to a registry with a version tag, like the shelf beside the container. Running hundreds of containers across many machines is the job of an orchestrator such as Kubernetes: see it schedule and heal them on The Cluster.

07 · ENVIRONMENTS

Environments and configuration

A change usually passes through several environments: dev (your laptop), staging (a copy of production for final checks) and production (real users). The golden rule: build once, promote the same image. On the stage, the same image id sits on all three platforms. What differs is configuration: which database, which API, how much to log.

The Twelve-Factor App puts it simply: keep config in the environment, never in the code. Its test: could you publish your code as open source right now without leaking a single password?

config.js

Production refuses to start, because LOG_LEVEL is missing. Add it and run again. Crashing at start-up, loudly, beats running half-configured.

.env
# .env · on your laptop only: listed in .gitignore, never committed
API_URL=http://localhost:8080
LOG_LEVEL=debug
DB_PASSWORD=local-dev-only    # production's comes from a secret store

08 · INFRASTRUCTURE AS CODE

Infrastructure as code

Servers, databases, networks and permissions used to be set up by hand in a web console. Nobody could say exactly how production was built, and nobody could rebuild it. Infrastructure as code (IaC) describes it in files instead, kept in git and reviewed like any other change.

Most IaC tools are declarative: you write the state you want, and the tool compares it with what exists and works out the steps. That comparison is the plan; carrying it out is apply. Here is the heart of it:

plan.js

Run it twice in your head: after apply, the plan is empty. Applying the same file again changes nothing. That property, idempotence, is what makes IaC safe to rerun.

main.tf
# main.tf · OpenTofu / Terraform (HCL)
resource "aws_instance" "web" {
  count         = 2                       # two identical servers
  ami           = var.server_image
  instance_type = "t3.small"
  tags = { Name = "web-${count.index + 1}" }
}
 
resource "aws_db_instance" "db" {
  engine            = "postgres"
  instance_class    = "db.t3.large"
  allocated_storage = 50                  # GiB
}

The best-known tool is Terraform. In August 2023 HashiCorp moved it from an open-source licence to the Business Source License; the community fork, OpenTofu, now lives at the Linux Foundation and reads the same files. Others: Pulumi (in ordinary programming languages), AWS CloudFormation, Ansible. Kubernetes runs the same compare-and-fix loop all day long.

09 · THE CLOUD

Cloud basics

The cloud is renting computers, storage and services from someone else's data centres, by the second, through an API. NIST's 2011 definition is still the clearest: on-demand self-service, broad network access, resource pooling, rapid elasticity and measured service. It names three service models: IaaS (rent virtual machines), PaaS (hand over your code and let the platform run it) and SaaS (use finished software). "Serverless" functions sit between PaaS and paying per request.

Clouds are split into regions (a city or area) and, inside each, availability zones: separate data centres with their own power, cooling and network, close enough to talk in a few milliseconds. On the stage, zone c goes dark and the load balancer keeps sending traffic to the other two. Spreading across zones is how you survive a fire, a flood or a cut cable:

availability.js

Redundancy multiplies the failure chances together (parallel). A chain of parts multiplies the success chances (series), so every part you add to the path of a request costs a little uptime.

The catch is in the comment: the maths assumes zones fail independently. Shared software, a shared configuration push or a shared dependency can take them all down at once. To see the hardware inside one of these halls, walk The Data Centre; for how requests reach it, How the Internet Works.

10 · DEPLOY STRATEGIES

Deploy strategies: blue-green, canary, flags, rollback

Deploying is the riskiest moment in a change's life, so teams make it small, gradual and reversible.

Blue-green: run two complete copies. Blue serves users; you deploy to green, check it, then switch the router. Rolling back is switching back. Canary: send a small share of real traffic (1%, then 5%, 25%, 50%) to the new version and compare it with the old before going further. On the stage, the router's green share grows step by step.

canary.js

As written, v42 is healthy and reaches 100%. Set NEW_ERROR_RATE to 0.02: the canary is caught at 1%, and 99% of users never see the bad release.

Feature flags separate deploying code from releasing a feature. The new code ships switched off, and a flag turns it on for chosen users or a percentage, with no deploy. The trick is to hash the user id, so each person gets the same answer every time:

flags.js

And always keep a rollback: a fast, practised way back to the last good version. On 19 July 2024 a faulty CrowdStrike content update went to every customer at once and crashed an estimated 8.5 million Windows machines. Among the fixes CrowdStrike promised afterwards: deploy such updates in stages, starting with a canary.

11 · MONITORING

Monitoring and alerting

Once it ships, you need to know it works without asking users. That is observability, built from three kinds of signal: logs (a line of text per event), metrics (numbers over time: requests per second, error rate, memory) and traces (one request followed across every service it touches). OpenTelemetry is the open standard for collecting all three.

Google's SRE book names four golden signals to watch on any service: latency, traffic, errors and saturation (how full it is). Latency needs care: averages hide pain. Use percentiles:

percentiles.js

The mean (120 ms) describes nobody. Most requests take about 70 ms, and one in a hundred takes over a second and a half.

A service level objective (SLO) is the target, like "99.9% of requests succeed over 30 days". The 0.1% left over is the error budget: room to take risks and ship. Alerts should fire on how fast you are spending it, the burn rate:

error-budget.js

At a burn rate of 14.4 for one hour you spend 2% of the month's budget, the paging threshold Google's SRE Workbook suggests. Try 0.003: bad, but a ticket for working hours.

Page a human only for things that need a human, now. Everything else is a ticket or a dashboard.

12 · INCIDENTS

On-call, incidents and postmortems

Somebody has to answer when the alert fires. Teams share that in an on-call rota, usually a week at a time. When something breaks badly, it becomes an incident, with clear roles: an incident commander who coordinates (and doesn't type fixes), people working the problem, and someone keeping everyone else informed.

The first goal is to mitigate: stop the harm, usually by rolling back, before you understand the cause. On the stage the router snaps back to v41, the red arc runs from the on-call desk to the router, and the graphs calm down. Then you find out why, and write it down:

timeline.js

Time to detect and time to mitigate are what you improve next time: better alerts shrink the first, practised rollbacks the second.

A postmortem follows every serious incident: the timeline, the impact, the causes and the actions that will stop it happening again, each with an owner. It is blameless. It looks for causes in the system (a missing check, a confusing tool) and assumes people did sensible things with what they knew. Blame teaches people to hide mistakes; the system only improves when they are told.

Ready to try it? On Call puts you at the console at 03:12 with five minutes to fix production, and writes the blameless postmortem from what you actually did.

13 · WHAT NEXT

The career map: what to learn next

You have now seen the whole journey, from a value in memory to a release watched by alarms. Above the floor, the career paths grow out of the stations they start from. Most of them share this chapter: every developer ships.

  • Front-end: HTML, CSS, a framework such as React, accessibility, performance. Back-end: APIs, databases, queues; chapters 11 to 14. DevOps and platform: containers, CI/CD, IaC, Kubernetes. SRE: monitoring, SLOs, incidents, capacity. Security: chapter 15, then threat modelling and secure review. Data: SQL, pipelines, statistics.
  • Go T-shaped: broad enough to follow a request through the whole system (Your Request's Journey shows one), deep in one part.

A portfolio is proof, not a list. Two or three real projects beat twenty tutorials: each live at a URL, with a README that says what it does and why, tests, a CI badge, and a short write-up of a hard bug you fixed. That write-up shows how you think, which is what an interviewer is trying to find out.

Open source is the closest thing to a real job you can do for free. Start small: fix a typo in the docs, reproduce a bug report, add a test. Look for issues labelled good first issue, read the project's CONTRIBUTING file, and ask before starting something big. Reviewers' comments are free mentoring.

Keep learning the way the course hub describes: retrieval, spacing and projects. Flashcards for what you want to keep, on a schedule like this one:

leitner.js

Make the third answer true and see the gaps grow. A wrong answer sends the card back to day one.

PRACTICE

Now you do it

Type the code yourself rather than pasting it: producing an answer builds memory that reading does not. Use the hints one at a time.

1

A three-way merge

Git merges by comparing both sides with the base: the version you both started from. Write merge3: if only one side changed the value, take that change; if both made the same change, take it; if they changed it differently, return "CONFLICT".

exercise-1.js
2

Find the circular import

A bundler walks imports depth-first. If a file imports itself through a chain, the walk would loop forever. Finish findCycle so it returns the loop, like ["cart.js", "price.js", "tax.js", "cart.js"], or null if there isn't one.

exercise-2.js
3

Make the Docker cache work for you

This Dockerfile reinstalls every dependency whenever any file changes, which can cost minutes on every build. Reorder the steps (and add one if you need to) so that editing src/server.js only re-runs the last two.

exercise-3.js
4

Judge a canary

Write the rule a deploy system runs at every step of a canary. Return "rollback" if the canary's error rate is more than double the baseline's, or if its p99 latency is more than 20% higher. Otherwise return "promote".

exercise-4.js
5

Should this wake someone up?

The SLO is 99.9%, so the error budget is 0.1%. Page the on-call engineer only when the burn rate (error rate ÷ budget) is at least 14.4 over the last hour and over the last five minutes, so a problem that has already stopped doesn't wake anyone.

exercise-5.js

RECALL

Check yourself, from memory

Answer each one before you open it. Then come back tomorrow, and again next week, and answer them cold: retrieval spaced over days is the most reliable study method we know of. Why that works.

Why does changing an old commit change the id of every commit after it?

What is the difference between continuous integration, continuous delivery and continuous deployment?

Why build one container image and promote it through every environment, instead of building for each?

Blue-green, canary, feature flag: what does each one switch?

Why is the p99 latency often more useful than the average?

What is the first goal in an incident, and what makes a postmortem blameless?

GO FURTHER

Resources

ON THIS SITE

See it running

SOURCES

Where the facts come from

  1. Git: hash function transition Git names content with SHA-1 (hardened since 2.13) and is moving to SHA-256.
  2. Git: git-diff, --diff-algorithm Myers is the default diff algorithm.
  3. Myers (1986), An O(ND) difference algorithm and its variations, Algorithmica
  4. Sadowski et al. (2018), Modern code review: a case study at Google, ICSE-SEIP Interviews, a survey and logs of 9 million reviewed changes.
  5. Bacchelli & Bird (2013), Expectations, outcomes, and challenges of modern code review, ICSE
  6. Martin Fowler, Continuous Integration (2000, revised 2024) Credits Kent Beck and Extreme Programming with developing the practice in the 1990s.
  7. DORA: software delivery performance metrics Change lead time, deployment frequency, failed deployment recovery time, change fail rate, deployment rework rate.
  8. The Twelve-Factor App: III. Config Config in the environment; the open-source litmus test.
  9. Docker docs: Build cache If a layer changes, all the layers after it are rebuilt too.
  10. Linux man-pages: namespaces(7)
  11. Linux kernel docs: Control Group v2
  12. Stack Overflow Developer Survey 2025: Technology Docker used by 71.1% of respondents, up 17 points from 2024.
  13. OpenTofu manifesto Terraform's licence changed from MPL to BUSL 1.1 on 10 August 2023; OpenTofu is the Linux Foundation fork.
  14. NIST SP 800-145, The NIST Definition of Cloud Computing (2011) Five essential characteristics, three service models, four deployment models.
  15. AWS: Availability Zones (fault isolation boundaries whitepaper) One or more data centres with separate power and networking, up to about 100 km apart.
  16. SEC order on Knight Capital Americas LLC (2013), Release 34-70694 New code missed one of eight servers; a reused flag woke old code; over $460 million lost in about 45 minutes.
  17. Microsoft: Helping our customers through the CrowdStrike outage (2024) An estimated 8.5 million Windows devices affected.
  18. CrowdStrike: Channel File 291 root cause analysis, executive summary (2024) Including the move to staged, canary-first deployment of content updates.
  19. AWS: Shared responsibility model
  20. Google SRE book: Monitoring distributed systems The four golden signals.
  21. Google SRE workbook: Alerting on SLOs Burn rate 14.4 over one hour spends 2% of a 30-day budget: page.
  22. Google SRE book: Managing incidents
  23. Google SRE book: Postmortem culture Blameless: causes, not culprits.
  24. OpenTelemetry: Signals Traces, metrics and logs.
  25. GitHub Docs: Encouraging helpful contributions with labels The good first issue label.
  26. Leitner system Sebastian Leitner's 1972 flashcard boxes.