Lesson 0006 · ~12 minutes · synthesis

Ship the decision, not the buzzword

One skill: given a feature brief, write a complete concurrency choice — tool, message design, lifecycle, and one risk you own.

Mission payoff

This is the durable skill from MISSION.md: defend an off-main-thread choice in a design review without hand-waving.

1. The playbook (four gates)

Run in order. Earlier gates reject more options than later ones.

Gate A · Problem

Is main-thread jank from pure work the issue? Or DOM/layout? Or offline? Measure; don’t worker a paint problem. (Lessons 1, 4)

Gate B · Tool

Dedicated = one page CPU. BroadcastChannel = tab notify. SharedWorker = one same-origin coordinator. Service worker = network/offline. (Lessons 1, 5)

Gate C · Channel

Clone by default; transfer big binaries; patches/chunks for huge high-frequency state. No functions/DOM on the wire. (Lesson 3)

Gate D · Ship

Bundler URL, same origin, typed protocol + errors, reuse workers, terminate/ports on leave. (Lessons 2, 4)

Sentence you should be able to say

“We use main | dedicated | shared | BroadcastChannel | SW because problem class; messages are clone | transfer | patches; we own lifecycle + bundler + one risk.”

Keep the print playbook open after this course — compressed form of all six lessons.

2. Practice — full briefs

Pick the best default package. Equal-length options.

Brief A · Analytics import

One-tab dashboard. User drops a 50 MB CSV; parse freezes UI 3s. Render a table from summary rows. SPA route can unmount.

Brief B · Multi-tab logout

User logs out in tab A; tabs B and C on the same origin must clear session UI quickly. No shared compute engine.

Brief C · Live feed, many tabs

Same-origin app; users open many tabs. Product wants one WebSocket to the server; all tabs show the feed.

Brief D · Editor state bus

Document model (~2 MB) lives in a worker. Team posts the entire document to main on every keystroke for render.

Brief E · List virtualizer

Proposal: move React list virtualization (measure nodes, write transforms) entirely into a dedicated worker.

Brief F · Offline shell

Product goal: cache app shell and work offline after first visit. No heavy client-side compute story.

3. Self-check (retrieval)

Without scrolling up — answer mentally, then expand.

After postMessage(u8, [u8.buffer]), what is u8.byteLength on the sender?

0 — the buffer was transferred (detached). Ownership moved.

Who calls terminate() vs close()?

Main thread: worker.terminate() (hard kill). Inside worker: close() (self-shutdown / discard queue).

When is BroadcastChannel enough instead of SharedWorker?

When tabs only need to notify each other — no shared process, single socket, or shared in-memory engine required.

4. What you can do now

Ask your teacher Paste a real feature from work (or an interview prompt). We will run the four gates on it together — that is how this becomes wisdom, not only fluency.

Primary source (course spine)

Re-skim web.dev — Off the main thread and the WHATWG workers intro as the architecture spine. Your print companion is decision-playbook.html.