Appearance
Workshop 3: Live demo script
Share-screen guide. Each step has a measurable before/after. Students mirror in their own forks and commit alongside you. The demo runs across blocks 3, 4, and 5.
Frame the numbers up front. The cold baseline is ~13 min, and that is deliberately, uncomfortably slow. ~95% of it (~12 min) is one stage: the serial real-HTTP test:api suite. The W3 steps below (caching, incremental tsc, no coverage, parallel workers, matrix/sharding, faster deploy) get the pipeline to roughly ~5–7 min, real progress, but they can't collapse test:api because the network round-trips are still real. The order-of-magnitude collapse to ~30s–2 min is Workshop 5, when we mock the SDK clients. Say that explicitly so today's win isn't oversold.
Setup before the demo
- Repo is forked and visible at
github.com/<my-handle>/orbittasks. - The slow baseline
.github/workflows/ci.ymlhas run at least once on my fork. I have the duration. - Editor is open on
.github/workflows/ci.yml. - Browser tab is on the Actions tab of my fork.
Step 1: Add dependency caching (Block 4, ~3 min)
"We're going to apply each optimization from the recipe, in order, and watch the duration drop. First up: dependency caching."
Edit
.github/workflows/ci.yml:yaml- name: Set up Node uses: actions/setup-node@v4 with: node-version: 20 cache: npm # <- add this lineCommit on screen:
git commit -am "ci: cache npm dependencies"and push.Switch to the Actions tab. Watch the workflow run.
When it finishes, point at the duration: expected drop of ~30–60 s on the install step.
Students follow along. Take 2 minutes for them to land their own commit.
Step 2: Enable incremental TypeScript (Block 4, ~3 min)
Edit
apps/api/tsconfig.json:json{ "compilerOptions": { "incremental": true, "tsBuildInfoFile": "./.tsbuildinfo" } }Add a cache step in the workflow for
.tsbuildinfo:yaml- uses: actions/cache@v4 with: path: '**/.tsbuildinfo' key: tsbuildinfo-${{ hashFiles('**/*.ts') }} restore-keys: | tsbuildinfo-Commit, push, watch. Expected drop: 30–60 s on typecheck on subsequent runs.
Step 3: Move coverage out of the PR path (Block 4, ~5 min)
"Coverage instrumentation costs ~30% of every test run. We don't need it on every PR; we need it nightly."
- Edit
apps/api/jest.config.js: changecollectCoverage: true→collectCoverage: false. - Edit
apps/web/vite.config.ts: changecoverage.enabled: true→false. - (Optional, save for later) Add
.github/workflows/coverage.ymlthat runs on a nightly schedule. - Commit, push, watch. Expected drop: 10–20 s on test:api, 5–10 s on test:web.
Step 4: Parallelize Jest and Vitest (Block 5, ~5 min)
- Edit
apps/api/jest.config.js: changemaxWorkers: 1→maxWorkers: '50%'(or delete the line entirely). - Edit
apps/web/vite.config.ts: the config advertises two serial knobs, so set bothsingleFork: falseANDisolate: false(it wassingleFork: trueandisolate: true). Flipping onlysingleForkleaves web isolating every file. - Commit, push, watch. Expected drop: test:api fans out across workers (the biggest W3 lever on the dominant stage); test:web drops a few seconds. It shortens
test:api, it does not collapse it; the round-trips are still real.
"Some tests will now run in parallel. If anything fails that didn't before, that's the lesson: find the shared state."
If a flaky failure shows up here, good. Pull up the failing test, walk through what's happening (probably a shared db instance not reset properly), and fix it on the spot. That's authentic engineering.
Step 5: Defer to Workshop 5 (~30 sec)
"Step 5 in the recipe, mocking all six external SDK clients, we save for Workshop 5. That's the one that takes
test:apifrom ~12 minutes to ~30 seconds, because it's the only step that stops the tests making real HTTP calls. Today's steps get us to ~5–7 min; Workshop 5 is the collapse. Skip for now."
This sets up Workshop 5's payoff. Don't try to do it here; the contrast is the point.
Step 6: Split CI into parallel matrix jobs (Block 5, ~5 min)
Restructure
.github/workflows/ci.yml:yamljobs: test: strategy: matrix: app: [api, web] runs-on: ubuntu-latest steps: # ... (full structure from starter/ci-optimized-reference.yml)Walk through the matrix structure live. Note that GitHub will now run two jobs in parallel.
Commit, push, watch. Expected drop: ~30 s wall-clock time.
Step 7 (optional polish, advanced): Shard the api tests
This one is optional and never required to keep up. If we have time and the cohort is moving well, we walk through --shard=N/M together. Otherwise skip; it's icing.
Step 8: Fix the slow deploy script (Block 5, ~2 min)
- Open
scripts/deploy.sh. Show the per-file copy loop withsleep 0.3. - Replace with
rsync -a "${SRC_DIRS[@]}" "$DEST". - Drop the smoke-check
sleep 5tosleep 0.5. - Commit, push, watch. Expected drop: ~25–30 s on deploy.
After the live demo
Open the Actions tab one more time. Show the side-by-side: original duration vs current. We record the two numbers in the W3 section of the logbook together; we reuse them in Workshop 6.
"From X minutes down to Y minutes. That's the win. Every step had a real reason."
Optional bonus: ask the room which step had the biggest impact for their fork. The answers vary based on the runner GitHub assigned: good teaching moment about why "your mileage may vary."