Lead Frontend Developer — Hard-Level Engineering & Interview Guide

Scratch to production · Architecture · System design · Internals · Leadership · Modern stack · 2026 edition

FAANG / Anthropic / Uber / Airbnb / ThoughtWorks bar Hard interview Lifecycle deep-dive 100+ reference links

Foreword

This guide is built for interviewing — and being — a Lead Frontend Engineer at the bar of companies like Anthropic, Facebook (Meta), Airbnb, Uber, Stripe, Vercel, and ThoughtWorks. It is intentionally harder than the average React-interview cheat sheet: it expects the candidate has shipped at scale, has opinions backed by production scars, and can reason from first principles.

The guide follows the natural arc of a frontend system from zero to production — each section covers decisions, trade-offs, hard questions, model answers, and deep-dive references. Use the navigation on the left; use the search box to jump fast. Every coloured reference link goes to canonical documentation (MDN, web.dev, React docs, Next.js docs, RFCs, engineering blogs).

Legend: 🔴 HARD means a typical Lead-level question. 🟡 STAFF means a question that separates Senior/Lead from Staff/Principal candidates. Plain questions are baseline Senior+.
How to use as the interviewer: pick one topic from Lifecycle, one from Deep Tech, and one from System Design. Spend ~20 minutes per area. Use the model answers to calibrate — but never read them verbatim.

01Project Inception — From Zero to Plan (Deep Dive)

The first 2–4 weeks of a frontend project determine the next 2 years. A Lead is judged less on writing code than on asking the right questions before any code is written. This section is the full curriculum for becoming exceptional at inception — read it in order, do the exercises, then re-read it before any project kickoff.

1.1

Why Inception Matters — The Cost of Skipping It

The cheapest bug to fix is the one in the requirements doc; the most expensive is the one shipped to production after a year of building the wrong thing. Inception is where you discover whether the project should exist, what success means, and what failure modes lie ahead — before you spend headcount on the wrong solution.

The Cost Curve of Decisions

This is the Boehm cost curve, popularized in software engineering since the 1980s and validated again at modern scale:

StageRelative cost to changeWhat's changeable here
Requirements / InceptionScope, problem definition, success metrics
Design3–6×Architecture, tech stack, team shape
Implementation10×Code structure, libraries
Testing / Pre-prod15–40×Bugs, integration issues
Production40–100×Behaviour fixes; customer trust; rework

The implication for Lead Engineers: aggressive investment in inception pays back disproportionately. Spending an extra week to nail down scope can save 3 months of rework downstream.

What You Are Actually Solving

Inception is the answer to four questions, in this order:

  1. Why? — What's the business or user pain that justifies headcount on this work?
  2. For whom? — Which user segment, in which context, with which devices?
  3. What does done look like? — A measurable definition of success.
  4. What is explicitly NOT in scope? — Non-goals.

If you can't answer all four in two sentences each, inception isn't complete. Most projects ship without satisfying #3 and #4 — and that's why they're declared "done" but feel unsuccessful.

Lead test: Pick a project on your roadmap. Can you state in three sentences what success looks like in measurable terms, who specifically benefits, and what's explicitly out of scope? If you hesitate, your team is one step from building on sand.
1.2

The Discovery Workshop — Step by Step

An inception workshop (also called a "kickoff workshop," "Lean Inception," or "Big Picture EventStorming") is a structured 2–5 day collaborative session that aligns engineering, product, design, and stakeholders before any building begins. ThoughtWorks popularized the modern version; Marty Cagan and Teresa Torres formalized the discovery half.

The Typical Agenda (Adapted from ThoughtWorks Lean Inception)

Day 1 — Why & Who

Vision, users, jobs-to-be-done

Write the elevator pitch. Identify primary & secondary personas. Map the jobs each persona is trying to accomplish.

Day 2 — The Problem Space

Goals, non-goals, current-state journey

Define the business objectives (NSM + supporting metrics). Walk the current user journey end-to-end on a wall. Identify pain points.

Day 3 — The Solution Space (Optional / Lighter)

Feature brainstorm, MVP scope, sequencing

Generate feature ideas; group by user benefit. Use MoSCoW or RICE to size and prioritize. Sketch the MVP.

Day 4 — Technical & Operational

Architecture sketch, risks, dependencies

High-level architecture (no commitments). Identify external dependencies. List the top 10 risks. Run a pre-mortem.

Day 5 — Synthesis

Engineering Brief + roadmap + next steps

Author the brief. Define the first 30/60/90 days. Identify open questions and decision owners.

The Inputs You Must Gather

  • Business objectives — what KPI moves if we ship this? Acquisition, activation, retention, revenue, cost-to-serve, NPS? Vanity vs north-star.
  • User research — primary personas, jobs-to-be-done, accessibility needs (locale, device, assistive tech), bandwidth profile, churn data.
  • Constraints — deadline (regulatory? market-event? competitive?), budget, headcount, vendor obligations, contractual SLAs.
  • Existing landscape — current systems (FE + BE), auth model, design system, observability stack, data warehouse, A/B platform.
  • Non-functional requirements — SLA, p95/p99 latency, geographic distribution, WCAG level, compliance (SOC 2, HIPAA, GDPR, PCI), RPO/RTO.
  • Definition of success — measurable; what does the org celebrate or count as a failure?

Outputs of the Workshop

  1. Product Engineering Brief (Section 1.6).
  2. User journey map (current & target).
  3. Prioritized feature backlog (MoSCoW or RICE-scored).
  4. Top-10 risk register.
  5. Architecture sketch (whiteboard-level — not code).
  6. 30/60/90 day plan.
  7. Open questions with named decision owners.
Try it yourself
  1. Pick a personal project (real or imagined — e.g., "a habit tracker for parents").
  2. Solo-run a 90-minute mini-inception: write the elevator pitch (1 paragraph), 3 personas, top 5 user jobs, target NSM, top 3 risks, 3 non-goals.
  3. Review the brief 3 days later — what feels obvious now that wasn't on day 1? That's the discovery payoff.
1.3

Stakeholder Mapping & Power Dynamics

Inception is also where you learn who can derail your project. Map this consciously — don't discover it three months in.

The Power × Interest Grid (Mendelow 1991)

Low interestHigh interest
High powerKeep satisfied — minimal but consistent updates; don't surprise themManage closely — frequent 1:1s, co-author key decisions
Low powerMonitor — broadcast updates sufficeKeep informed — they'll surface useful info; valuable allies

For every stakeholder you can name, plot them in this grid. The biggest project killers are high-power / low-interest people whose "no" can stop everything — they need a relationship before there's a problem.

The Modern Lead's RACI

RACI = Responsible, Accountable, Consulted, Informed. Draw it for every major decision. Anti-pattern: too many A's (no clear owner) or too many C's (decision paralysis).

RoleOwnsLead FE's relationship
Product ManagerProblem, priorities, scopeDaily collaboration; you push back on scope.
Design LeadUX, IA, design system inputsNegotiate feasibility; flag a11y & perf tax.
Backend LeadAPI contracts, data modelCo-design API shape; advocate for FE ergonomics.
Platform / DevOpsCI/CD, infra, observabilityDefine FE deploy strategy within their constraints.
SecurityThreat model, complianceEngage early; CSP, auth, data residency need sign-off.
Data / AnalyticsInstrumentation, A/B platformDefine tracking schema as part of feature spec.
QA / SDETTest strategy, automationCo-author testing pyramid; align on E2E ownership.
Legal / PrivacyCookie banner, T&C, data residencyLoop in for any new tracking or third-party.
Customer SupportUser pain at the coalfaceOften your best source of "what's actually broken."
Marketing / GrowthSEO, performance marketing constraintsInfluences URL design, rendering strategy, analytics.
Finance / ProcurementVendor approval, budgetTool/CDN/observability spend goes through them.

Reading the Org Chart

The org chart is a political map. Three signals to read:

  • Reporting line of the sponsor. A VP-sponsored project survives reorgs; a director-sponsored project may not.
  • Cross-functional dependencies. Every team you depend on has its own priorities. Map them at inception so you're not surprised when they don't ship.
  • Skip-level allies. A senior staff engineer two levels above can unblock you faster than your direct manager. Build relationships before you need them.
1.4

Requirements Engineering — Asking the Right Questions

The deepest skill in inception is asking questions that surface what people haven't said. PMs underspecify; users articulate symptoms not causes. A Lead's questioning instinct is what separates a good kickoff from a great one.

The 5 Whys (Sakichi Toyoda, Toyota Production System)

For every stated requirement, ask "why?" five times. Each "why" pushes from feature → outcome → underlying problem.

EXWorked Example

PM: "We need a dark mode toggle."

Why? Users have asked for it.

Why? Some complain the app is too bright at night.

Why? They use it in bed before sleep.

Why? Our session metrics show 28% of sessions are 10pm-2am.

Why? Our users use the app to wind down — they're not work-focused at that hour.

Real requirement: Reduce eye strain and respect circadian context — which could also be auto-dim, blue-light filtering, or a "calm mode" beyond just dark.

The Mom Test (Rob Fitzpatrick)

Three rules for questions that get real answers, not the answers people think you want:

  1. Talk about their life, not your idea.
  2. Ask about specifics in the past, not opinions about the future.
  3. Talk less, listen more.

Bad: "Would you use a feature that…?" (Yes — they're being polite.)
Good: "Tell me about the last time you tried to do X. What happened?"

5W2H — A Requirements Checklist

  • What exactly are we building?
  • Why are we building it? (Business and user)
  • Who will use it? Who is responsible for it?
  • Where will it run? (Device, geography, network conditions)
  • When does it ship? Driven by what?
  • How will we know it worked?
  • How much — cost, scope, performance budget?

Questions a Senior Lead Always Asks

  • "What does failure look like for this project?"
  • "If we could only ship one thing, which one would it be?"
  • "What's the cost of doing nothing?"
  • "Has anyone tried to solve this before? What happened?"
  • "Who's the most opinionated stakeholder we haven't consulted yet?"
  • "What would change our mind about this approach?"
  • "What's the deadline driven by? Is it real?"
  • "Whose budget pays for this? Whose headcount?"
  • "What happens to this project if [key person] leaves?"
  • "What are we NOT going to do?"
Drill: The Probe Ladder
  1. Take a 1-line feature request from your current backlog ("Add a filter to the dashboard").
  2. Generate 10 clarifying questions across the 5W2H grid.
  3. Rank them by which would most change your implementation if answered.
  4. Take the top 3 to your PM. Notice how the conversation shifts.
1.5

Prioritization Frameworks — Picking What to Build First

Prioritization is the most leveraged conversation in inception. A Lead doesn't just rubber-stamp the PM's list — they bring frameworks that make trade-offs explicit and defensible.

MoSCoWMust / Should / Could / Won't

Classify each requirement. Forces the team to commit to a "Won't" list — usually the most revealing column. Best for early-stage scoping.

Pitfall: Everything becomes a "Must." Rule: no more than 60% of effort in Must; if higher, the project is over-scoped.

RICEReach × Impact × Confidence ÷ Effort

Used at Intercom, popularized in product. Each feature scored:

  • Reach — users affected per time period.
  • Impact — 0.25 (minimal), 0.5, 1 (medium), 2, 3 (massive).
  • Confidence — 50%, 80%, 100%.
  • Effort — person-months.

Forces explicit reasoning. Excellent for mid-project re-prioritization meetings.

ICEImpact × Confidence × Ease

Lighter-weight RICE, used at Sean Ellis's growth-hacking framework. Useful when reach is similar across options.

KANOBasic / Performance / Excitement

Categorizes features by user reaction:

  • Basic / Threshold — required for the product to be acceptable. Users don't notice them; their absence kills the product.
  • Performance / Linear — more = better. Speed, storage, completeness.
  • Excitement / Delighters — unexpected, raise satisfaction non-linearly. Become "Basic" over time.
  • Indifferent — users don't care; cut these.
  • Reverse — users dislike these (unwanted complexity).

Use to ensure you have the right mix — all Basic + no Excitement = forgettable product; lots of Excitement + missing Basics = broken.

WSJFWeighted Shortest Job First (SAFe)

(Cost of Delay) ÷ Job Size = priority score. Cost of Delay = User-Business Value + Time Criticality + Risk Reduction. Designed for backlogs of similar-sized items where time pressure varies. Common in enterprise / regulated environments.

OPPOpportunity Solution Tree (Teresa Torres)

Tree: Desired Outcome → Opportunities (user needs/pains) → Solutions → Experiments. Forces continuous discovery — never jump straight to solutions. Excellent for navigating from a goal (NSM) down to validated, testable feature ideas.

Choosing a Framework

SituationPick
Early scoping, mixed stakeholder roomMoSCoW (simple, communicable)
Comparing many features quantitativelyRICE
Fast lightweight rankingICE
Ensuring product is satisfyingKano
SAFe / regulated environmentWSJF
Continuous discovery, outcome-drivenOpportunity Solution Tree
Tactical sprint planningEisenhower (urgent × important)
Drill: Score Your Backlog
  1. Take 8 items from your current backlog (real or invented).
  2. Score each using RICE.
  3. Re-rank from your current order.
  4. Identify the biggest mismatch — that's where political priority is overriding objective priority.
  5. Decide: is that mismatch justified by context, or should you push back?
1.6

Writing the Product Engineering Brief

The brief is the single artifact of inception. Done right, it survives reorgs, prevents scope creep, and serves as a calibration point for every future decision. Aim for 4–8 pages. Below 4 pages = under-thought; above 8 pages = nobody reads it.

The Canonical Template

# <Project Name> — Engineering Brief
Owner: <name>  ·  Status: Draft / Approved  ·  Last updated: <date>

## 1. TL;DR (3 sentences max)
What we're building, who for, why now.

## 2. Problem Statement
The user / business pain in 1–2 paragraphs. Cite evidence
(metrics, support tickets, user interviews). No solutions yet.

## 3. Users & Jobs-to-be-Done
Primary persona(s) and the specific jobs they're hiring this
product to do.

## 4. Goals
Measurable success criteria (leading + lagging metrics).
"We will know this worked when X moves from Y to Z by <date>."

## 5. Non-Goals
Explicit list of what we are NOT solving in this project.
The most-referenced section after launch.

## 6. Solution Sketch
High-level approach (no architecture yet — that's the next doc).
1–2 paragraphs + a sketch if helpful.

## 7. Open Questions
Top 5–10 unanswered questions, each with named owner and due date.

## 8. Risks & Mitigations
Top risks (technical, organizational, market) with mitigation
plans or "accepted risk" call-outs.

## 9. Milestones & Sequencing
30 / 60 / 90 day plan with dependencies. No specific dates yet.

## 10. Stakeholders & Decision Owners
RACI for the major decisions.

## 11. Appendix
Research, links to design docs, ADRs, related projects.

What Makes a Brief Good

  • Specific, not aspirational. "Reduce checkout abandonment from 32% to 25% by Q3" beats "Improve checkout."
  • Cites evidence. Every claim ("users want X") has a citation (ticket, survey, interview, metric).
  • Has named owners. Every open question has a person and a date.
  • Acknowledges what's unknown. Pretending to know what you don't kills credibility.
  • Reads in 15 minutes. If a senior leader can't get the gist in 15 minutes, it's too long.
  • Has a kill criterion. "We'll stop this project if metric X hasn't moved by Y." Engineering honesty.

Design Docs vs ADRs vs RFCs vs Engineering Briefs

DocumentScopeLifespan
Engineering BriefThe whole project; why & whatThe whole project (months/years)
Design DocHow to build a major component / featurePre-build through launch
RFC (Request for Comments)Proposed change across teams; cross-cutting decisionsDays to weeks; archived after decision
ADR (Architecture Decision Record)One decision + context + consequencesPermanent — historical record
One-Pager / PitchSell an idea to leadershipUntil decision

Reference: Will Larson — Design Docs at Stripe · Industrial Empathy — Design Docs at Google · Pragmatic Engineer — Scaling via RFCs

1.7

Non-Goals — The Most Underrated Section

The fastest way to spot a senior Lead is to read their non-goals section. It signals discipline, focus, and the courage to disappoint stakeholders deliberately.

Why Non-Goals Are Hard

  • Stakeholders don't ask for non-goals — they ask for goals.
  • Writing "we won't build X" feels like a defeat in a culture that rewards ambition.
  • Non-goals require political will — you'll have to defend the omission.
  • Without them, scope drifts silently. With them, anyone trying to add scope must explicitly remove the "won't."

Good Non-Goals Are Specific

Bad non-goalGood non-goal
"Optimize performance""INP below 200ms for users on mid-tier Android" (this is a goal)
"Not redesigning""We will NOT redesign the existing search UI; we'll reuse the v3 component library as-is"
"No mobile""We will NOT build native iOS/Android in this project; the web app must work on mobile browsers"
"Skipping i18n""This release ships en-US only; non-English locales come in v2 (Q3 2027)"

Common Non-Goal Categories

  • Platforms — what platforms / browsers / devices we won't support.
  • Performance — explicit "we won't optimize below X" budget.
  • Edge cases — which low-frequency user paths we'll defer.
  • Accessibility — what level (AA but not AAA, e.g.).
  • Internationalization — locales not supported in v1.
  • Integrations — third parties we won't connect to.
  • Migration — what we'll leave on the old system.
  • Backwards compatibility — what we'll break.
A useful exercise: every time someone proposes a new feature, ask "what does this push to a non-goal?" Forces zero-sum thinking when scope is treated as infinite.
1.8

Defining Success — Metrics, OKRs, North Stars

Inception without a measurable definition of done is inception by vibes. A Lead nails this before a line of code.

The Metrics Pyramid

LevelWhatExample (e-commerce)
North Star Metric (NSM)One number that reflects product value delivered"Repeat-purchase revenue per active customer"
L1 / Driver metrics2–4 metrics that move the NSMConversion rate, AOV, retention, frequency
L2 / Feature metricsMetrics tied to a specific featureCart-abandonment-rate, checkout completion time
Health / Counter metricsWhat you'll watch for unintended damageRefund rate, support ticket volume

Leading vs Lagging Indicators

  • Leading — predicts future state. Page-view time, scroll depth, button clicks. Move fast — useful for in-quarter steering.
  • Lagging — confirms what already happened. Revenue, retention, NPS. Move slow — useful for definitive proof.

A Lead aligns the team on leading metrics weekly, lagging metrics quarterly. Reporting only lagging metrics is steering by looking in the rear-view mirror.

Writing Good OKRs

Objective + 3–5 Key Results. Objective is qualitative ("Delight power users"); Key Results are specific, quantitative, time-bound.

BadGood
"Improve performance""p75 LCP for the catalog page drops from 3.4s → 2.0s by end of Q3"
"Increase engagement""Weekly active users with ≥3 sessions grows from 22% → 30% by end of Q3"
"Ship the redesign""95% of organic traffic served by the new design system by end of Q3 with no regression in conversion"

Reference: John Doerr — What Matters (OKRs) · Measure What Matters book

The Goodhart Trap

"When a measure becomes a target, it ceases to be a good measure." — Charles Goodhart. If you reward "lines of code shipped," you'll get bloat. If you reward "tickets closed," you'll get split bugs. Defend against this by: (1) pairing every target metric with a guardrail metric, (2) reviewing metrics qualitatively each quarter for gaming, (3) rotating which metrics matter most.
1.9

Pre-Mortems — Imagining Failure Before You Start

A pre-mortem (Gary Klein, 2007 HBR) is the inverse of a post-mortem: you imagine the project has failed catastrophically, then work backwards to figure out why. Surfaces risks that optimistic planning hides.

How to Run One

  1. Gather the team (engineering + product + design) for 60 minutes.
  2. State the prompt: "It is 12 months from now. This project has failed catastrophically. The team is being disbanded. Why?"
  3. Silently — for 10 minutes, each person writes their top 5 reasons. (Silence first prevents groupthink.)
  4. Round-robin: each person shares one reason. Cluster on a whiteboard.
  5. Vote: each person gets 3 dots; place on the most-worrying clusters.
  6. For top 3 risks, draft mitigation plans with owners.
  7. Capture in the brief's risk register.

Common Pre-Mortem Findings (FE-flavored)

  • "We over-invested in the design system and shipped no user-facing features."
  • "The backend team's API was 8 weeks late; we couldn't ship without it."
  • "Performance regressed silently because we didn't set budgets."
  • "We picked Module Federation but only one engineer understood the failure modes."
  • "We never validated the design with real users; the redesign tanked conversion."
  • "Our hiring loop took 6 months; we shipped late by exactly that."
  • "Stakeholder X never bought in; quietly blocked us for the whole project."
  • "We migrated mid-flight to a new framework; doubled scope."
A senior Lead runs pre-mortems even on small projects. The 60-minute investment routinely catches risks that would cost weeks.
1.10

Estimation Under Uncertainty

Estimation in inception is the single most-faked skill in software. Junior leads quote a number; senior leads quote a distribution.

The Cone of Uncertainty (Boehm)

At project start, estimates are accurate within a factor of 4×. By design phase, 2×. By implementation, 1.25×. Estimates given at inception are inherently coarse — communicate that explicitly.

Three Estimation Modes

ModeUse whenOutput
T-shirt sizingEarly inception, no designS / M / L / XL — for relative ranking only
Story points (relative)Team has shipped together, has velocity baseline1 / 2 / 3 / 5 / 8 / 13 — Fibonacci-style
Reference class forecastingComparing this to similar past projects"This is like the X project we did, which took 4 months"
Bottom-up time estimatesDesign is locked, scope is fixedSpecific hours/days — with a buffer factor

Reference Class Forecasting (Kahneman / Flyvbjerg)

Rather than estimating from scratch ("how long will this take?"), find similar past projects and use their actual duration. This corrects for the "planning fallacy" — humans systematically underestimate by 30–80%. Bent Flyvbjerg's research on mega-projects (How Big Things Get Done) shows this is the single most accurate forecasting method available.

The "Steel Thread" Approach

Rather than estimating the whole project, build one minimal end-to-end slice ("steel thread") through every layer in 1–2 weeks. The act of building it tells you what the system actually looks like; estimates after are based on evidence, not imagination.

Communicating Estimates

  • Always give a range, never a point. "4–6 weeks at 80% confidence" not "5 weeks."
  • State the assumptions explicitly. "Assumes the API spec is locked by Monday; if it slips, add a week per week of slip."
  • Distinguish forecast from commitment. A forecast can be wrong; a commitment cannot be without consequence.
  • Track actuals. Compare your past estimates to actuals; this calibrates future estimates.
Drill: Calibrate Your Estimation
  1. Pull your last 10 tickets. Estimate each from scratch as if you hadn't shipped it.
  2. Compare to actual time. Calculate the average ratio.
  3. For the next sprint, multiply every estimate by that ratio.
  4. Re-measure at the end. Repeat until ratio is < 1.3 or > 0.8.
1.11

Risk Mapping & Mitigation

A senior Lead names risks before stakeholders ask. The risk register is a living document — first drafted in inception, updated weekly during execution.

Risk Categories (FE-flavored)

CategoryExamples
TechnicalUntested architecture, library still pre-1.0, perf budget at risk
DependencyBackend API not ready, design system not stable, vendor SLA risk
Resource / PeopleCritical engineer leaving, hiring slip, skill gap on team
ScheduleHard external deadline, conflicting projects competing for same resource
OrganizationalSponsor change, reorg, conflicting priorities
Market / CompetitiveCompetitor ships first; user expectations shift
Compliance / LegalGDPR/CCPA changes, accessibility lawsuits, security audit
OperationalIncident during launch, CDN outage, third-party SDK breaking

Risk Score = Probability × Impact

For each risk, score on 1–5 scales for probability and impact. Multiply. Sort by score; focus on top 5.

The Four Risk Strategies

  • Avoid — change the plan to remove the risk. ("Drop the experimental library.")
  • Mitigate — reduce probability or impact. ("Spike the risky integration in week 1.")
  • Transfer — make someone else's problem. ("Move auth to a vendor.")
  • Accept — document the risk, do nothing. ("Acknowledged: vendor SLA could degrade. Owner: VP Eng.")

The Risk Register (Template)

| ID  | Risk                              | Cat | P | I | Score | Strategy | Owner | Status |
|-----|-----------------------------------|-----|---|---|-------|----------|-------|--------|
| R01 | API not ready by week 6           | Dep | 4 | 5 | 20    | Mitigate | Sara  | OPEN   |
| R02 | Design system v3 breaks v2 callers| Tec | 3 | 4 | 12    | Mitigate | Mark  | DONE   |
| R03 | Single Bus Factor on TanStack mig | Peo | 3 | 5 | 15    | Mitigate | Lead  | OPEN   |

Reference: PMI — Risk Analysis · Will Larson — Mapping Risk

1.12

Conway's Law & Team Topology

Conway's Law (1968): "Organizations design systems that mirror their communication structure." If you have 3 teams, you'll build a 3-component system whether or not that's optimal. A Lead applies this intentionally — design the team structure to produce the architecture you want.

The Inverse Conway Maneuver

Coined by Jonny LeRoy + Matt Simons (ThoughtWorks): structure your teams the way you want your software to be structured. Want microfrontends with strong independence? Have small teams with full-stack ownership of their MFE. Want a unified UX? Have a single product team with embedded specialists.

Team Topologies (Skelton & Pais)

Four fundamental team types — the model used at Spotify, Microsoft, Capital One, Netflix:

TypeMissionLifespanFE example
Stream-alignedOwns a slice of customer value end-to-endLong-lived"Checkout team" owns from cart to receipt
PlatformInternal product for stream-aligned teamsLong-livedDesign system team, dev-tools team, build platform
EnablingHelps other teams adopt new tech/practiceTemporary — 3 months"a11y enablement," "RSC migration squad"
Complicated-subsystemOwns a domain requiring deep specializationLong-livedVideo player team, payments team, real-time sync team

Interaction Modes (only 3)

  • Collaboration — high bandwidth, short term, for discovery; high cost, use sparingly.
  • X-as-a-Service — one team provides a contract; consumers self-serve. Most relationships.
  • Facilitating — enabling team helps a stream team for a fixed period.

Reference: teamtopologies.com · Skelton & Pais — Team Topologies (book)

Cognitive Load is the Currency

A team has a finite cognitive budget. Adding scope = adding cognitive load. Beyond a threshold, throughput drops. Team Topologies prescribes: size the team's responsibilities to fit its cognitive load, not the other way around.

Practical Implications for a Lead in Inception

  • Sketch the team boundaries alongside the architecture sketch. They co-evolve.
  • Avoid "spaghetti teams" where everyone touches everything — Conway's Law produces spaghetti software.
  • Decide platform/stream split early. Will the design system live in a platform team or be co-owned across stream teams?
  • Limit interaction modes — every additional collaboration relationship is overhead.
1.13

Building Shared Understanding — Event Storming & Story Mapping

Two techniques every senior Lead should be able to facilitate. They turn vague problem spaces into shared visual artifacts the whole team can reason about.

Event Storming (Alberto Brandolini)

A workshop technique for discovering domain events. Used heavily in Domain-Driven Design but invaluable for FE architecture too.

  1. Get everyone — eng, product, design, ops — into one room with a long wall and orange sticky notes.
  2. Each sticky represents a domain event, written in past tense ("Order Placed", "Payment Confirmed", "Shipment Notified").
  3. Place events left to right in rough timeline order.
  4. After 30 minutes, layer in: commands (blue, what triggered the event), actors (yellow, who issued the command), policies (purple, the business rules).
  5. Identify hot spots — questions, contradictions, gaps — with red stickies.
  6. The output is a domain map the whole team can refer to for the rest of the project.

Reference: eventstorming.com · Brandolini — Introducing EventStorming (free PDF)

User Story Mapping (Jeff Patton)

Map the user's journey horizontally; layer features vertically by release.

             User Activities (horizontal — left→right in user time)
        +-------+-------+-------+-------+
        | Find  | Try   | Buy   | Use   |
        +-------+-------+-------+-------+
Backbone| story | story | story | story |    ← essential MVP slice
        +-------+-------+-------+-------+
Walking | story | story | story |       |    ← release 2
Skeleton| story | story |       |       |    ← release 3
        +-------+-------+-------+-------+

The "backbone" is the minimum viable journey. Releases are horizontal slices — each delivers a complete user journey. Avoids the trap of shipping a partial app (e.g., a great search page with no checkout).

Reference: Jeff Patton — Story Mapping · Patton — User Story Mapping (book)

Choosing Between

  • Event Storming — when domain complexity is high (financial, healthcare, multi-actor flows).
  • Story Mapping — when user journey is the primary axis (consumer products, SaaS apps).
  • Combine for complex consumer products.
1.14

The Tech Lead's Inception Toolkit

A checklist of tools / techniques to carry into every kickoff. Don't show up empty-handed.

The Documents Toolkit

  • Engineering Brief template (Section 1.6).
  • RACI matrix for decision ownership.
  • Risk register.
  • Open Questions log with named owners.
  • Stakeholder map (Power × Interest grid).
  • ADR template for individual decisions as they're made.
  • 30/60/90 plan template.

The Workshop Toolkit

  • Silent brainstorming → cluster → vote (avoid groupthink).
  • Lightning talks (5-min framings, one per stakeholder).
  • Affinity mapping (group stickies by similarity).
  • Dot voting (each person 3 dots).
  • Fist of five (1–5 fingers for agreement; explicit consensus check).
  • Round-robin readouts (forces every voice in the room).
  • Parking lot (capture off-topic thoughts; revisit at end).

The Mental Toolkit

  • Chesterton's Fence — don't tear down something until you understand why it was built.
  • Hill chart (Basecamp) — visualize uncertainty: tasks are "uphill" (figuring out) before "downhill" (executing).
  • 5 Whys — for digging past surface symptoms.
  • Wardley Maps — for strategic positioning of components (commodity vs custom).
  • Cynefin framework — classify problems: simple / complicated / complex / chaotic. Each needs a different response.

Reference: learnwardleymapping.com · Cynefin framework · Basecamp — Hill Charts

The Facilitation Toolkit

  • Reading a room — who's quiet? Who dominates?
  • Calling on people gently when silent expertise is in the room.
  • Timeboxing aggressively — set a timer; honor it.
  • Naming the discomfort ("I notice we're avoiding the budget conversation").
  • Closing every workshop with: decisions made, decisions deferred, owners, dates.
1.15

30/60/90 Day Plans

The 30/60/90 plan is the inception artifact for execution. Every project needs one; every new hire needs their own.

Standard Shape

PhaseThemeOutcomes
Days 0–30Listen & LearnMap systems, build relationships, ship a small visible win
Days 31–60Diagnose & PlanIdentify 2–3 strategic levers; propose plan; align stakeholders
Days 61–90Execute & DemonstrateShip first major milestone; demonstrate trajectory

For a New Project (the Lead's plan)

Days 0–30 · Discovery & Foundation

Inception, hiring, foundation

Complete inception workshop. Draft Engineering Brief. Initial RFC for architecture. Set up CI/CD scaffolding. Hire / onboard first engineers.

Days 31–60 · Steel Thread

End-to-end thin slice

Ship the steel thread — one user flow through every layer (auth → fetch → render → submit → persist). Validates architecture; produces real estimates.

Days 61–90 · MVP Build-out

Expand from the thread

Layer in features around the steel thread. Internal alpha by day 75. External beta by day 90. Reviewed against the success metrics.

For a New Hire

  • Days 0–30: Ship one small PR by end of week 1. Complete onboarding doc with feedback. Map the codebase. 1:1 with 8–10 cross-functional partners.
  • Days 31–60: Own a small feature end-to-end. Run a code review for a peer. Propose one improvement to a process.
  • Days 61–90: Lead a medium feature. Mentor an earlier-career engineer. Demonstrate independent technical judgment in design discussions.

Reference: Michael Watkins — The First 90 Days

1.16

Influence Without Authority

A Lead has positional authority over zero people they need to influence — designers, PMs, backend leads, infra. You influence via reputation, evidence, and well-told stories.

The Six Sources of Influence

From Influencer (Patterson et al.). Influence comes from:

  1. Personal — motivation: connect what they need to what you want.
  2. Personal — ability: teach them to do what you need (don't assume they can).
  3. Social — motivation: peer norms, public commitments.
  4. Social — ability: coalitions, allies, sponsors.
  5. Structural — motivation: incentives, recognition.
  6. Structural — ability: remove obstacles; design the path.

Tactics That Work

  • Write the doc first. A clear written proposal is harder to argue against than a verbal pitch.
  • Bring data, not opinion. "Our p95 LCP is 4.2s" beats "I think we're slow."
  • Pre-wire decisions. Have 1:1 conversations with key stakeholders before the meeting where the decision is made. Surface objections privately.
  • Frame in their language. Talk to PM in business outcomes. Talk to security in threat models. Talk to design in UX impact.
  • Trade favors. Help others on their roadmap items; ask for help when you need it.
  • Make their job easier. If you can hand a stakeholder a ready-to-approve doc instead of a question, they'll say yes.
  • Make the path of least resistance the path you want. Defaults matter — make the right thing easy.

Tactics That Backfire

  • Escalating to a manager before trying peer dialogue.
  • Being right but condescending.
  • Refusing to compromise on small things — burns credit for the big ones.
  • Treating disagreement as personal opposition.
  • Ignoring people you think are wrong instead of engaging them.

The "Disagree and Commit" Pattern

Used at Amazon, Anthropic, Stripe. When a decision is made you don't agree with: voice the disagreement clearly once; if you lose the argument, commit fully to execution. Don't undermine the decision behind closed doors. Reference: Amazon Leadership Principles — Have Backbone; Disagree and Commit

1.17

The Art of the First Week

Whether you're a new Lead joining a team or a returning Lead on a new project, week one is disproportionately important. People form lasting impressions in the first 7–10 days.

The First-Week Playbook

  1. Listen 80%, talk 20%. Resist the urge to demonstrate competence.
  2. Book 1:1s with every engineer on the team. 30 minutes each; ask: what's working, what's broken, what would you change?
  3. 1:1 with each cross-functional partner. Same questions, different lens.
  4. Ship something small. Even a documentation fix or a CI improvement. Signals you're a builder, not just a talker.
  5. Read everything. Engineering briefs, ADRs, runbooks, RFCs, recent postmortems. Three days of reading saves three months of confusion.
  6. Resist the rewrite urge. Whatever feels wrong, write it down — but don't act on it for 90 days.
  7. Set explicit expectations. Tell your team how you work, your office hours, how to escalate, what kinds of decisions you'll defer to them.
  8. Find your sponsor + your skip-level mentor. Build the relationships you'll need before you need them.

What NOT to Do in Week One

  • Propose a major reorg / migration / tool change.
  • Dismiss the existing architecture publicly.
  • Promise outcomes you don't yet understand the cost of.
  • Skip 1:1s "because you're busy onboarding."
  • Take credit for any pre-existing work in flight.

The "Listening Tour" Questions

  1. What does success look like for you in this role / project?
  2. What's the smartest thing the team did in the last year?
  3. What's the dumbest thing the team did in the last year?
  4. If you could change one process, what would it be?
  5. Who on the team is underutilized / under-recognized?
  6. Who's a flight risk?
  7. What should I read first?
  8. What's the elephant in the room nobody talks about?
  9. How do you like to receive feedback?
  10. What's the best thing I could do for you in my first 90 days?

Reference: Will Larson — Onboarding Engineering Leadership · Pragmatic Engineer — First 90 Days

1.18

Common Inception Anti-Patterns

Patterns to recognize — in yourself and others — before they bite.

Anti-patternWhat it looks likeFix
Solutioning before problemTeam is debating React Server Components in week 1; no one has met a user.Hard rule: no architecture before the brief is approved.
Boil the oceanScope keeps expanding; "while we're at it…" added 5 times.Re-read the non-goals section weekly. Add any new ask to non-goals or kill it.
Phantom consensusNobody disagrees in the meeting; everyone has reservations privately.1:1 pre-wiring. Explicit "fist of five" voting. Designate a devil's advocate.
HiPPO (Highest Paid Person's Opinion)VP weighs in; team caves immediately.Bring data. Frame counter-arguments as "let me understand the constraint" not "you're wrong."
Magical estimates"It'll take 6 weeks." How? Why 6? Nobody knows.Insist on range + assumptions. Reference-class forecast.
Stakeholder absenteeismSecurity / Legal / Data not in the room until pre-launch; they block everything.Invite them in week 1. Even if they only listen, they're not surprised later.
Sequential discovery + delivery"We'll finish discovery, then build" — discovery has no end date.Time-box discovery. Continuous discovery throughout build.
Skipping the brief"We're agile, we don't need docs." Three months later, nobody remembers the original goal.Even a 1-page brief is better than zero. Make it lightweight, not bureaucratic.
Optimism cascadeEach team padded their estimate, but together they still overshoot.Pre-mortem. Steel-thread first. Track velocity.
Solution dogmatism"We always do X" — without checking if X fits this problem.Force a "why not the alternative?" section in the brief.
The hero PM/LeadOne person holds all context; team is rudderless without them.Document everything. Force decisions to be written, not verbal.
"Plan once, ship once"The brief is treated as gospel after week 4; reality has shifted but nobody updates it.Weekly brief check: any non-goal moved? Any assumption broken? Any risk activated?
1.19

Hard Questions Bank — Inception-Specific

Walk me through how you'd kick off a greenfield consumer web product expected to scale to 50M MAU in 18 months.
Model: Frame as discovery → architecture choice → MVP scope. Discovery: profile target users (geo, device, network — 50M MAU likely means heavy mobile-web, emerging markets, INP & data budget matter). Architecture choice: rendering strategy driven by SEO (RSC/SSR if discoverable, SPA if behind auth), CDN-first delivery, edge auth, multi-region static distribution. MVP scope: 3 features exercising the entire critical path (auth, data write, data read with cache). Build the steel thread first; defer optimizations off the hot path. Set perf budgets day one. Define "shippable" = p75 LCP < 2.5s on Moto G Power, INP < 200ms.
How do you decide between greenfield rewrite and incremental migration of a legacy FE?
Model: Rewrite if (a) the old stack is no longer hireable, (b) coupling makes incremental change cost-prohibitive, (c) a strategic re-platform window exists. Otherwise: strangler fig. Wrap the legacy app in a shell that owns routing; replace surfaces one at a time. Most rewrites fail — see Joel Spolsky's "Things You Should Never Do". The Lead's job is to make this an explicit decision with criteria, not a gut call.
A PM hands you a 30-page spec on day one. What do you do?
Model: Don't argue with the artifact — extract the essence. Map every requirement to MoSCoW. Identify the 3 features that, if shipped, prove the thesis. Push the rest to backlog. Run an alignment session with PM + Design + Backend to confirm the trimmed list. Document the MoSCoW decision so it's auditable. Surface assumptions that the spec made implicitly.
You're asked to deliver a project in 3 months that you estimate at 6. How do you handle it?
Model: Don't push back with "no" — push back with options. (1) Cut scope: show what the 3-month version looks like and what it explicitly won't have. (2) Add resources: how many extra engineers would it take (with the warning that "9 women can't make a baby in a month"). (3) Accept risk: state the assumptions that, if all hold, get you there — and flag what happens if they don't. (4) Push back on the date: ask what's driving it; sometimes the date is more flexible than communicated. Surface this in writing so the trade-off is explicit. Reference: Will Larson on writing decision-quality docs.
Your sponsor changes mid-project. What's your playbook?
Model: First, re-validate the brief with the new sponsor. They may not share the previous sponsor's priorities. Re-baseline goals and non-goals against the new context. Identify which of your existing commitments are at risk. Communicate the risk to the team early — don't pretend continuity. Update the risk register. If the new sponsor wants a meaningfully different direction, propose a re-inception (1-week light) rather than continuing under a misaligned goal.
How do you reconcile design's desire for ambitious UX with engineering's need to ship?
Model: Frame as a shared optimization, not a tug-of-war. Run a joint workshop where designers see the cost (perf budget, time, complexity) of each "ambitious" piece. Engineers see the user impact data behind each. Categorize: Must-have (high impact, manageable cost) / Nice-to-have (low cost, ship it) / Defer (high cost, weak data — re-evaluate). The Lead's role is to keep both sides at the same table; if you let them negotiate via Slack, neither understands the trade-offs. Create a "design tax" budget — explicit % of effort allocated to UX polish above functional minimum. Spend it knowingly.
Your team disagrees on the architecture. The split is 4 vs 3. How do you decide?
Model: Don't decide by vote — decide by argument quality. Have both sides write a 1-page proposal: context, decision, consequences, alternatives considered. Often, putting it in writing collapses the disagreement (people realize they're not as far apart as they thought). If both proposals are credible, run a 2-week timeboxed PoC. If still split: as the Lead, make the call and document it as an ADR. Never let architectural disagreements simmer past 2 weeks; they corrode the team.
The CEO says "ship it by EOQ" with no scope flexibility. Engineering says it's impossible. You're in the middle. What do you do?
Model: Translate, don't take sides. To the CEO: "Here's exactly what we can ship by EOQ at the current scope, with these assumptions, and here's what's at risk. If any of these slip, we have a contingency plan: [X]." To engineering: "Here's why EOQ matters externally. Let's identify the minimum we can ship that meets that bar — and what we'd defer to v1.1 in week 1 of next quarter." If neither side will budge, escalate the trade-off in writing. The Lead's failure mode is to commit to both without making the trade-off visible.
1.20

Practice Exercises — Run Your Own Inception

Reading about inception teaches the patterns; running one builds the muscle. Pick three exercises and complete them before declaring yourself fluent.

Exercise A · The 90-Minute Solo Inception
  1. Pick a real or imagined product (e.g., "an offline-first notes app for journalists in conflict zones").
  2. Set a 90-minute timer. Use this structure:
    • 15 min: elevator pitch, 3 personas, top 5 jobs-to-be-done
    • 15 min: NSM + 3 driver metrics
    • 20 min: top 10 features brainstormed; RICE-scored
    • 15 min: 5 non-goals
    • 15 min: top 5 risks with mitigations
    • 10 min: write the 1-page Engineering Brief
  3. Put it aside for 48 hours. Re-read and revise.
  4. Show a peer; ask for the 3 most-questioned assumptions.
Exercise B · The 5-Whys Drill
  1. List the last 5 feature requests you received from PM/stakeholders.
  2. For each, do the 5 Whys to dig past the surface ask.
  3. Reframe each request as the underlying problem statement.
  4. Identify which of your reframings the original requester would agree with — and which would surprise them.
Exercise C · The Pre-Mortem on a Real Project
  1. Pick your current biggest project.
  2. Write 10 reasons it could fail catastrophically.
  3. Score each by probability × impact.
  4. For the top 3, write a mitigation plan.
  5. Discuss with your manager / PM. Did they have any in mind that you missed?
Exercise D · Stakeholder Map for a Real Project
  1. List every person who can affect or is affected by your current project.
  2. Plot each on the Power × Interest grid.
  3. For each high-power person, audit: when did you last 1:1 with them? What's your shared context?
  4. Schedule the missing conversations this week.
Exercise E · Write an ADR Retroactively
  1. Pick a technical decision your team made in the last 12 months (framework choice, library swap, architecture pattern).
  2. Write the ADR retroactively: context, decision, alternatives considered, consequences.
  3. Share with the team. Often surprises emerge: people remember the rationale differently.
  4. If the ADR feels weak — the original decision lacked rigor. Make new decisions to a higher standard.
Exercise F · Run an Event Storming Mini-Session
  1. Pick a single user flow in your product (e.g., "user signs up and completes onboarding").
  2. Get a virtual whiteboard (Miro / FigJam) or sticky notes on a wall.
  3. Solo, write every domain event (past tense) on orange stickies — 15 minutes.
  4. Add actors (yellow), commands (blue), policies (purple).
  5. Mark hot spots (questions, contradictions) in red.
  6. You'll find at least 3 things you didn't realize you didn't know.
Exercise G · Build a Personal "Inception Kit"
  1. Create a folder of templates: Engineering Brief, ADR, RACI, Risk Register, Pre-Mortem agenda, 30/60/90 plan.
  2. Each template should be 1 file, <1 page, ready to copy-paste.
  3. Store in your dotfiles / personal Notion / GitHub repo.
  4. Pull from this kit on day 1 of every project. Refine after each use.
1.21

Full Resource Library — Books, Courses, Talks, Articles

The exceptional Lead reads constantly. Below is the curated curriculum — pick one item from each category per quarter for sustained growth.

Frontend Masters Courses (most-relevant for Lead/Tech Lead)

Frontend Masters · Course
Engineering Management 101
Jem Young (Netflix)
Navigate the engineer-to-manager transition. People leadership skills, day-to-day responsibilities, meeting management, common first-manager pitfalls.
Frontend Masters · Course
Enterprise Engineering Management
Ryan Burgess (Netflix)
Setting up teams with OKRs, KPIs, team charters, hiring processes, fostering strong partnerships. The closest thing to a Tech Lead masterclass on FE Masters.
Frontend Masters · Course
Complete Intro to Product Management
Brian Holt
Understand the PM side of the table. Communication, data-driven metrics, planning, project vs product management distinctions.
Frontend Masters · Course
Product Design for Web Applications
Mike Hartington
The iterative product design cycle — discovering needs, prototyping, iterating, launching, monitoring, refining. Closes the gap with design partners.
Frontend Masters · Path
Enterprise & Leadership Learning Path
Frontend Masters
The full curated path: lead projects and teams at scale. Includes management, architecture, design systems, monorepos.
Frontend Masters · Path
Expert Learning Path — Lead/Staff Developer
Frontend Masters
Microfrontends, monorepo applications, migration strategies, code quality enforcement. The technical depth side of the Lead role.

Other Online Courses

Course
The Principal Dev — Certification Masterclass
Daniel Terhorst-North
Cohort-based, project-grounded program for Tech Leads. Covers strategic thinking, technical leadership, organizational influence. Multi-week investment but high-quality.
Course
LeadDev Learning
LeadDev
Workshops on leading without authority, scaling teams, technical decision-making. Built specifically for engineering leaders.
Course
StaffEng Guides
Will Larson
Free essays on the Staff+ engineering tracks — archetypes, promotion narratives, the technical and political work of staff engineers.
Course
Digital Product Management Specialization
UVA Darden (Coursera)
University-grade product management curriculum. Includes discovery, prioritization, metrics, OKR systems. Counterweight to engineering-only education.

Essential Books

Book
Inspired
Marty Cagan
The product-management gospel. How great products get built. Required reading for understanding what good PM partners do.
Book
Empowered
Marty Cagan
Sequel to Inspired. How to build the kind of org where strong product teams thrive. Useful for senior Leads influencing org design.
Book
Continuous Discovery Habits
Teresa Torres
The how-to for continuous discovery. Opportunity Solution Tree, customer interviews, assumption testing. Practical and immediately applicable.
Book
The Mom Test
Rob Fitzpatrick
A 130-page masterclass on asking questions that get real answers. Short, sharp, immediately useful in every stakeholder conversation.
Book
Shape Up
Ryan Singer (Basecamp · free online)
Basecamp's approach to shaping work before it goes to engineering. Hill charts, betting table, 6-week cycles. Read it free.
Book
Staff Engineer
Will Larson
The defining text on the Staff+ engineer track. Archetypes, narratives, the political and technical work that matters at scale.
Book
The Manager's Path
Camille Fournier
The canonical engineering management book. Even if you don't go management, you need to understand what your manager does.
Book
An Elegant Puzzle
Will Larson
Engineering management as systems thinking. Organizational design, team rituals, growth conversations. Anecdote-rich.
Book
Team Topologies
Skelton & Pais
The definitive book on how to structure software teams. Stream-aligned, platform, enabling, complicated-subsystem. Cited in every modern org design discussion.
Book
Accelerate
Forsgren, Humble, Kim
The DORA research distilled. Why deployment frequency, lead time, MTTR, and change-failure-rate predict org performance. Data-grounded.
Book
How Big Things Get Done
Bent Flyvbjerg & Dan Gardner
Reference-class forecasting, planning fallacy, why mega-projects fail. Best estimation book for engineers since Mythical Man-Month.
Book
Thinking, Fast and Slow
Daniel Kahneman
The cognitive biases every Lead encounters in inception meetings — planning fallacy, anchoring, availability heuristic. Bedrock reading.
Book
The First 90 Days
Michael Watkins
Hardvard Business School classic on onboarding into a leadership role. Used by senior leaders at almost every Fortune 500.
Book
Measure What Matters
John Doerr
OKRs from the source — Doerr learned them at Intel under Andy Grove, brought to Google, now everywhere. Practical examples.
Book
Influencer
Patterson, Grenny, Maxfield, McMillan, Switzler
Six-source model of influence. Foundational for influence-without-authority, the core Lead skill.
Book
Crucial Conversations
Patterson et al.
How to handle high-stakes disagreements. The exact skill needed when scope, deadlines, or architecture decisions get heated.

Foundational Articles & Essays

Essay
Inception — The Key to Starting a Project Right
ThoughtWorks
The canonical write-up on the Inception workshop technique. From the firm that popularized it.
Essay
Strategies, Stories & Design Docs
Will Larson
How to write an engineering strategy. Templates and examples from Stripe-era Larson. The most-shared design-doc essay on the modern web.
Essay
Design Docs at Google
Malte Ubl
How Google does design docs. The pattern: lightweight, async, accountable. Set the global standard for tech-co design docs.
Essay
Scaling Engineering Teams via Writing Things Down (RFCs)
Gergely Orosz
Why RFCs matter for scaling org coordination. Templates, anti-patterns, what good looks like at Uber-scale.
Essay
Lead Development Team
Martin Fowler
Fowler's framing of what a Lead Developer is and does. Older essay; still the cleanest definition.
Essay
Things You Should Never Do — Part I
Joel Spolsky
The classic warning against full rewrites. Mandatory reading before any "let's rewrite it from scratch" decision.
Essay
Strangler Fig Application
Martin Fowler
The pattern for incremental migration. Replace legacy systems by wrapping, not rewriting. Essential vocabulary.
Essay
Performing a Project Pre-Mortem (HBR)
Gary Klein
The 2007 HBR article that introduced the pre-mortem. 4 pages; foundational.
Essay
The Agile Fluency Model
James Shore & Diana Larsen
How teams mature through agile capabilities. Useful for diagnosing why a team's process isn't working.
Essay
Mapping Risk & Impact
Will Larson
A senior engineer's framework for thinking about risk vs impact in project prioritization.
Essay
The Pragmatic Engineer — Project Kickoff
Gergely Orosz
Practical templates and patterns for project kickoff at modern tech companies.
Essay
Onboarding Engineering Leadership
Will Larson
The first 30/60/90 days as an engineering leader. What to read, who to meet, what to ship.

Conference Talks & Videos

Talk · MIT (free)
How to Speak
Patrick Winston · MIT
The hour-long MIT lecture every engineer-turned-leader should watch. How to structure talks, win arguments, communicate technical ideas. Free.
Talk · StaffPlus
StaffPlus Conference Talks
LeadDev
Annual conference for Staff+ engineers. The talk archive covers technical strategy, influence, architecture decisions at scale.
Talk · LeadDev
LeadDev Conferences
LeadDev
London / NYC / Berlin / SF — annual engineering leadership conferences. Talk videos free on YouTube; the management-meets-tech track is unmatched.
Talk
Conway's Law in Action
Mel Conway / various
Walkthrough of Conway's Law applied to modern software organizations. Foundational concept for any tech lead.
Talk · QCon
QCon Conference Archive
InfoQ
Deep technical talks from senior engineers at FAANG/Anthropic/Stripe/Uber. Architecture, migration, scaling stories.
Talk · GOTO
GOTO Conferences
GOTO
European software conference with strong leadership / architecture tracks. Free YouTube archive.
Talk
Death by Powerpoint (and how to fix it)
David JP Phillips · TEDx
For every Lead who has to present to leadership. 20 minutes; will change how you build decks forever.
Talk
The Art of Pragmatic Engineering Leadership
Gergely Orosz · various
Pragmatic Engineer's collected wisdom on leadership. Look for his conference talks on YouTube.

Podcasts

Podcast
LeadDev Podcast
LeadDev
Bi-weekly interviews with engineering leaders. Cross-cutting topics — hiring, scope, architecture, conflict.
Podcast
The Pragmatic Engineer Podcast
Gergely Orosz
Deep interviews with engineering leaders at Stripe, GitHub, Anthropic, Linear. Concrete behind-the-scenes accounts.
Podcast
Soft Skills Engineering
Dave Smith & Jamison Dance
Listener questions about the non-technical side of engineering. Funny, practical, weekly. Covers everything inception-adjacent.
Podcast
Lenny's Podcast
Lenny Rachitsky
Top product-management podcast. Useful for understanding the PM side of the table — what your PM partners are reading.
Podcast
The Changelog
Changelog
Long-running interview show with open-source maintainers and engineering leaders. Technical depth with leadership themes woven in.
Podcast
The Stack Overflow Podcast
Stack Overflow
Conversational technical podcast covering the breadth of software engineering and industry trends.

Newsletters Worth Subscribing

Newsletter
The Pragmatic Engineer
Gergely Orosz
Twice-weekly, paid. The standard for behind-the-scenes engineering culture at big tech. Every Lead reads it.
Newsletter
Refactoring
Luca Rossi
Weekly engineering management newsletter. Tactics, frameworks, and mental models for tech leads.
Newsletter
Engineering Leadership
Gregor Ojstersek
Practical short essays on tech leadership. Diagrams-heavy; quick reads.
Newsletter
The Deployed Team
Various
Engineering management essays focused on remote/distributed teams.
Newsletter
Lenny's Newsletter
Lenny Rachitsky
Top product-management newsletter. Cross-functional perspective every Lead needs.
Newsletter
Working in Content
Erika Hall
Erika Hall's writing on research, communication, organizational behavior. Sharp, contrarian, useful.

Communities

  • Rands Leadership Slack — invitation-based; thousands of engineering managers and leaders. Most active community for the topic.
  • LeadDev Community — conference-affiliated; tracks for Staff/Lead/EM topics.
  • StaffEng community — Will Larson's resource hub; comments and discussion on staff-track topics.
  • r/ExperiencedDevs — anonymous candor on the harder parts of engineering leadership.
  • Local LeadDev / Meetup communities — meeting in-person remains the highest-bandwidth way to learn.

The 90-Day Inception Curriculum

If you have 90 days to level up at inception specifically — pick this curriculum:
  1. Days 1–14: Read Inspired + The Mom Test + Shape Up. Watch Patrick Winston's "How to Speak."
  2. Days 15–28: Take Engineering Management 101 on Frontend Masters. Run Exercise A (the 90-Minute Solo Inception).
  3. Days 29–45: Read Team Topologies + How Big Things Get Done. Run Exercise D (Stakeholder Map) on your current project.
  4. Days 46–60: Read Continuous Discovery Habits. Take Complete Intro to Product Management on Frontend Masters.
  5. Days 61–75: Read Staff Engineer. Subscribe to Pragmatic Engineer + LeadDev + Refactoring.
  6. Days 76–90: Co-facilitate an inception workshop with a peer or mentor. Apply Exercises B, C, E, F to a real project.
After 90 days, you'll be ahead of 95% of engineers in your peer group on this dimension. Compounded over a career, the gap is enormous.

02Tech Stack Selection

Tech stack is a 5-year decision dressed as a 2-week task. The Lead's job is to make this decision visible, justified, and reversible where possible.

2.1 The Decision Axes

AxisWhat you're optimizing forCommon answers (2026)
Rendering strategySEO, TTFB, time-to-interactive, server costRSC + streaming SSR (Next.js App Router, Remix/RR7), SSG (Astro), pure SPA (CRA-style with Vite — only for auth-walled apps)
FrameworkHireability, ecosystem, perf characteristicsReact still dominant; Vue 3 strong in EU/Asia; Svelte 5 ascending; SolidJS for perf-critical; Qwik for resumability
Meta-frameworkRouting, data, deploy story bundledNext.js (default), Remix→React Router 7, TanStack Start, Astro (content), SvelteKit, Nuxt (Vue)
LanguageType safety, refactor confidenceTypeScript — non-negotiable at lead level
StylingBundle, DX, RSC compatibilityTailwind v4, CSS Modules, vanilla-extract, Panda CSS; CSS-in-JS legacy = styled-components/emotion
UI primitivesAccessibility, customizabilityRadix UI, React Aria (Adobe), shadcn/ui, Headless UI, Ark UI
State (client)Subscriber granularity, DXZustand, Jotai, Redux Toolkit, XState (machines)
State (server)Cache, dedup, invalidationTanStack Query, RTK Query, Apollo (GraphQL), SWR, Relay (large scale)
FormsPerf, validation, schema reusereact-hook-form + Zod; TanStack Form; Conform (RSC-friendly)
Build / bundleCold start, HMR, prod sizeVite, Turbopack, Rspack, esbuild, Rollup (libs)
Test runnerSpeed, ESM, watch DXVitest (modern), Jest (legacy stronghold), Playwright (E2E), Storybook test-runner
Lint / formatCI speed, rule depthBiome (modern), ESLint flat config + Prettier (legacy), oxlint (emerging)
MonorepoCode sharing, CI graphTurborepo, Nx, pnpm workspaces + changesets, Moon, Bazel (mega-scale)
DeploymentEdge vs node vs staticVercel, Cloudflare Pages/Workers, Netlify, AWS (CF+S3+Lambda@Edge), self-host (Kubernetes)

2.2 The 9-Question Decision Framework

Borrowed from Spotify's tech-radar process and adapted for FE:

  1. Does it solve our actual problem? Not "is it cool" — "does the constraint exist?"
  2. What is the total cost of ownership over 3 years? Licensing, hosting, hiring, switching costs.
  3. How big is the community? Stack Overflow tag count, npm weekly downloads, GitHub contributors, conference talks last 12 months.
  4. What is the bus factor? One maintainer = high risk. Foundation-backed (Linux Foundation, OpenJS) = safer.
  5. What does the next version look like? Roadmap public? Breaking changes telegraphed?
  6. How does it interop with the rest of the stack? Does it force decisions in adjacent layers (Next.js forces Vercel-friendly choices)?
  7. What does the exit look like? Can we migrate off in 6 months if needed?
  8. How does it perform on our hot path? Build a tracer-bullet prototype and measure.
  9. Who already knows it on the team? Internal capability is a free advantage.

2.3 Anti-patterns Lead Candidates Should Articulate

  • Resume-driven development: picking the technology because it's hot, not because it fits.
  • Sunk-cost decisions: "we already started with X, so we must continue" — even when X is failing.
  • Lowest-common-denominator: picking only what the most junior engineer already knows — caps ambition.
  • "Just use whatever": the inverse of analysis paralysis. Lead candidates have opinions backed by evidence.

2.4 Hard Questions

You're choosing between Next.js App Router and Remix (now React Router 7) for a B2C marketplace. Walk me through the decision.
Model: Next.js wins on RSC maturity, edge ecosystem, image optimization, and Vercel's commercial polish. Remix/RR7 wins on web-fundamentals philosophy (forms, progressive enhancement, no client-side waterfalls), simpler mental model, hostable anywhere. For a marketplace: if SEO + RSC streaming for product pages is the hot path, Next.js. If frequent forms and you want progressive enhancement out of the box (resilient to JS failures), Remix. Cite real production deployments: Notion uses Next, Shopify Hydrogen forked Remix. Discuss vendor lock-in honestly: Next.js's best features (ISR, image opt, edge middleware) work best on Vercel.
Your CTO wants to standardize the company on Svelte to "differentiate." You disagree. How do you handle it?
Model: Don't dismiss; quantify. Build a one-page risk register: hiring market (LinkedIn data), ecosystem (npm download trends, library availability), migration cost (sample component re-implementation timing), reversibility (can we move back to React in 12 months?). Present the data; let the CTO decide informed. Lead's job is not always to win the argument — it's to make sure the org isn't deciding blind. Reference: StaffEng archetypes — the Right Hand.
Pick three libraries you've adopted in the last 12 months and three you've dropped. Tell me why.
Listening for: evidence of evaluation, post-mortem honesty, ecosystem awareness. Strong answer cites specific perf measurements, bundle size impact, DX issues, or breaking-change patterns. Weak answer is "we used React Query because it's popular."

2.5 References

03Architecture & ADRs

Architecture is the set of decisions that are expensive to reverse. A Lead documents them so the next Lead doesn't have to re-derive them.

3.1 Architecture Decision Records (ADRs)

Introduced by Michael Nygard in 2011 (canonical post). Every significant decision gets a numbered Markdown file in docs/adr/:

# ADR-0023: Adopt Module Federation for Cross-Team UI Sharing

## Status
Accepted — 2026-04-10

## Context
We have 6 product squads each shipping their own React app. Shared components
are copy-pasted across repos and drift. Build-time npm packages cause coordinated
deploys and a 30-minute release cycle.

## Decision
Adopt Module Federation (Webpack 5 / Rspack) to load shared remotes at runtime.
Host the design system as a federated remote consumed by all six apps.

## Consequences
+ Independent deploys of design system without consumer rebuild.
+ Sub-second hot-swap when a fix ships.
- Runtime coupling: a broken remote breaks consumers.
- Shared deps (React, Router) require strict version negotiation.
- New observability requirement: track remote load failures per consumer.

## Alternatives Considered
- Build-time npm packages with changesets (current state): rejected — release coupling.
- Web Components: rejected — interop friction with React state.
- Single-spa: rejected — heavier than Module Federation for our use case.

## References
- Module Federation docs: https://module-federation.io/
- Zack Jackson talks on YouTube (creator)
- Our PoC results: docs/poc/module-federation-2026-Q1.md

3.2 The Frontend Architecture Layers

Modeled after the C4 model adapted for FE:

LayerWhat lives hereKey questions
DeliveryCDN, edge functions, DNS, TLS terminationWhere does first byte come from? How is HTML cached?
Runtime shellApp shell, routing, layout, error boundariesWhat loads before any feature code? Critical path?
Feature modulesPage/feature folders, route bundlesHow are features isolated? Lazy loaded? Owned?
State & dataServer state, client state, derived stateWhat's cached where? Invalidation strategy?
Design systemTokens, primitives, components, patternsHow are components versioned? Migrated?
Cross-cuttingAuth, i18n, feature flags, analytics, error trackingHow does a feature opt in/out? How is consent honored?
Platform & toolingBundler, lint, test, CI, deployReproducible builds? Cache hits? Test parallelism?

3.3 Composition Patterns at Scale

Monolith SPA

Single repo, single bundle, single deploy. Best for teams < 15 engineers. Communication is implicit (function calls). Breaks down when independent release cadence becomes necessary.

Monorepo + Modular App

One repo, many packages (Turborepo / Nx). Apps share design system and utilities at build time via workspace deps. Single deploy artifact, but contributors are isolated. Current default at most companies.

Reference: monorepo.tools · Turborepo docs · Nx mental model

Micro-Frontends — Build-Time

Each MFE published as npm package; integrating app composes them at build. Versioned via SemVer. Pros: type-safe, performant. Cons: coordinated deploys, slow release.

Micro-Frontends — Run-Time (Module Federation / Native Federation)

Remotes loaded at runtime via Webpack/Rspack Module Federation or Native Federation (Angular). Independent deploys. Shared dependency negotiation is the hard problem.

Reference: Module Federation · Cam Jackson on Micro-Frontends (Martin Fowler) · micro-frontends.org

Micro-Frontends — Edge-Side Composition (ESI / Edge-Side Includes)

HTML fragments composed at the CDN edge. Used by Spotify, Zalando. Powerful for SSR-heavy properties; complex to operate.

Reference: Zalando — Tailor architecture · ESI W3C spec

Islands Architecture

Static-first HTML with interactive "islands" hydrated independently. Astro, Fresh, Marko. Excellent for content sites where most HTML is static.

Reference: Jason Miller — Islands · Astro Islands docs

Resumability (Qwik)

Skip hydration entirely — serialize the framework state into HTML. Client picks up where server left off. Theoretical O(1) startup regardless of app size.

Reference: Qwik resumability

3.4 The Hard Architectural Trade-offs

Trade-offOne sideOther side
Independence vs CoherenceMFEs let teams ship independentlyUsers see inconsistent UX; shared deps fragment
Edge vs OriginEdge = low latency, cheap, geo-localOrigin = full Node runtime, easier debugging
RSC vs SSR vs CSRRSC = smaller JS, server data fetchRSC = harder to reason about, ecosystem still maturing
Monorepo vs PolyrepoMono = atomic refactor, shared toolingPoly = isolated CI, smaller blast radius
Run-time MFE vs Build-timeRun-time = independent deployBuild-time = type safety, smaller risk
Custom design system vs adoptCustom = brand controlAdopt (Radix/Aria) = cheaper, better a11y

3.5 Hard Questions

Design the FE architecture for a company with 50 product squads shipping daily, sharing a brand, but with independent product roadmaps.
Model: Three layers — (1) Platform layer: shared design system + auth + analytics + feature flag SDK as runtime contracts (versioned, federated). (2) Product layer: each squad owns a vertical, deployed independently, behind a path-based router (e.g., /checkout, /dashboard). (3) Shell layer: a thin orchestrator owning navigation, global notifications, and cross-squad communication via a typed event bus. Discuss: how do you enforce visual consistency? (visual-regression tests on shared components, Chromatic baseline shared across squads, design-token contract tests). How do you handle independent React versions? (React 19 forward-compatible singletons via Module Federation shared scope OR each MFE owns its React via Web Components — discuss trade-offs). Cite Spotify Backstage as a precedent for the platform pattern.
Why is Module Federation harder than it looks in production?
Model: (1) Shared dependency hell — React, React-DOM, Router must be singletons; version mismatches crash at runtime with cryptic errors. (2) Type sharing — federated remotes need their types built and published separately; can't import remote types statically. Solutions: @module-federation/typescript-plugin or contracts via OpenAPI-like schema. (3) Independent versioning paradox — if Remote A and Remote B both depend on a shared lib at different majors, the host has to pick one. (4) Observability — when a remote fails, the host needs a fallback boundary per remote. (5) Performance — every remote is an extra HTTP request; prefetch on idle, share the React chunk via the host. (6) Security — remotes execute JS in your origin; subresource integrity is impossible because you don't know the hash until runtime. Often you add a remote allowlist.
When would you NOT use micro-frontends?
Model: When the org problem isn't there. MFEs solve independent deploy and team autonomy. If the team is < 20 people, if the product is one cohesive surface, if deploys aren't bottlenecked — MFEs add cost without benefit. Cam Jackson's article is explicit: "if your problem is technical complexity, MFEs make it worse." Also avoid MFEs for high-perf product surfaces (checkout, primary funnel) where every KB matters.

3.6 References

04Foundation Setup — Day 1 to Week 4

The platform decisions made before any feature ships will be inherited by 100 future engineers. A Lead invests in foundation as if onboarding the team they don't have yet.

4.1 The Day-One Checklist

  1. Repo created; default branch protection on; required reviewers configured.
  2. Conventional commits enforced via commitlint.
  3. Node version pinned (.nvmrc + engines field) and reproduced in CI.
  4. Package manager pinned (packageManager field in package.json — Node 16.9+).
  5. TypeScript with strict: true; noUncheckedIndexedAccess, exactOptionalPropertyTypes on.
  6. Linter + formatter: Biome OR ESLint flat config + Prettier; rules committed.
  7. Pre-commit hooks: Husky + lint-staged (or simple-git-hooks).
  8. CI pipeline running on PRs from minute one — even if it just lints.
  9. Renovate or Dependabot configured for dependency PRs.
  10. License file, README, CODEOWNERS, CONTRIBUTING.md.
  11. Security: npm audit in CI, Snyk/Socket integration, SBOM generation.
  12. Editor config: .editorconfig, recommended VS Code extensions in .vscode/extensions.json.

4.2 TypeScript Configuration (Production-Grade)

{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2023", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "jsx": "react-jsx",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "isolatedModules": true,
    "verbatimModuleSyntax": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "incremental": true,
    "paths": {
      "@app/*": ["./src/app/*"],
      "@ui/*": ["./src/ui/*"]
    }
  }
}

Reference: tsconfig reference · Total TypeScript — tsconfig cheatsheet

4.3 CI Pipeline Anatomy

StageToolsTarget time
Installpnpm + frozen lockfile + actions/cache< 30s
Lint & Type-checkBiome / ESLint + tsc --noEmit< 45s
Unit testsVitest with sharding< 90s
BuildVite / Turbopack with cache< 2min
E2E (smoke)Playwright against built artifact< 3min
Visual regressionChromatic / Playwright snapshotsparallel to E2E
Bundle analysisstatoscope / size-limit / bundlewatch< 30s
Securitynpm audit + Snyk + SAST (Semgrep)< 60s
Deploy previewVercel / Netlify / custom S3+CF< 90s

Target: PR-to-feedback < 5 minutes. Anything slower kills iteration velocity.

4.4 Hard Questions

Your CI pipeline takes 25 minutes. Engineers are merging without it finishing. Diagnose and fix.
Model: First, instrument — break down where time goes (most CI providers expose per-step timing; Turborepo & Nx have built-in cache hit metrics). Common wins: (1) Dependency install — switch to pnpm, cache ~/.pnpm-store keyed by lockfile hash. (2) Test parallelism — Vitest --shard across 4–8 runners; Playwright workers + sharding. (3) Affected-only — Turborepo/Nx affected commands; only test what changed. (4) Build cache — Turborepo remote cache to S3 or Vercel; cache hit rate > 80% target. (5) Drop unnecessary steps from PR runs — visual regression only on main, security scan nightly. (6) Container reuse — buildx / Docker layer cache. (7) Hardware — bigger runners cost less than engineer wait time. Set a budget (5 min PR), instrument adherence, alert on regression.
An engineer ships a config change that breaks the build for everyone. How does your system prevent this and recover?
Model: Prevention: (1) required CI green before merge; (2) merge queues (GitHub Merge Queue, Aviator, Mergify) test the actual mainline state pre-merge; (3) config changes go through a CODEOWNERS gate. Recovery: (1) revert is the first action — not "fix forward"; (2) every commit on main must be revertible (no semantic coupling to subsequent commits); (3) bisect-friendly history (no force-push, small commits). Long-term: invest in change-cost reduction — fast revert, fast rollback, gradual rollout.

4.5 References

05Design System & UI Foundation

A design system is product infrastructure — not "a folder of components." A Lead treats it with the same rigor as an API.

5.1 The Layered Token Architecture

The mature pattern adopted by Material 3, Adobe Spectrum, Carbon, and Polaris:

TierExampleOwner
Reference / Primitivecolor.blue.500 = #2563ebBrand / Design
System / Semanticcolor.action.primary = {color.blue.500}Design System team
Componentbutton.primary.bg = {color.action.primary}Design System team
ThemeDark mode override of system tokensDesign System team

Tools: Style Dictionary, Tokens Studio (Figma), Specify, W3C Design Tokens spec.

5.2 Component Architecture Patterns

Headless / Behavior + Presentation Split

Modern best-practice. Headless libraries (Radix UI, React Aria, Headless UI, Ark UI) own behavior, accessibility, keyboard, focus. Your team owns visuals. The split lets the design system evolve visually without re-implementing accessibility every time.

// Headless + styled (shadcn/ui style):
import * as Dialog from '@radix-ui/react-dialog';

export function ConfirmDialog({ children, ...props }) {
  return (
    <Dialog.Root {...props}>
      <Dialog.Overlay className="overlay" />
      <Dialog.Content className="content">
        {children}
        <Dialog.Close className="close" />
      </Dialog.Content>
    </Dialog.Root>
  );
}

Compound Components

Parent component coordinates child state via Context. Used by Reach UI, Radix, Headless UI, and any modern Tabs/Accordion/Select.

Polymorphic Components (“as” prop)

Allow consumer to render the component as any HTML element. Hard to type correctly — see Ben Ilegbodu — polymorphic components in TS. React Aria uses a different pattern (slots).

Slot Pattern

Allow the parent to pass an element rather than children, useful for swapping the underlying element while keeping props/behavior. Implemented in Radix via asChild.

5.3 Storybook in Production

  • Every component has stories that double as documentation and as tests via interaction testing.
  • Visual regression via Chromatic, Percy, or Playwright snapshots gated on PR.
  • a11y addon running axe-core on every story.
  • Component testing mode for running stories as test fixtures.
  • Story-driven design reviews — designers approve in Chromatic UI before merge.

5.4 Hard Questions

A product team wants to fork a button component because they need a slightly different shape. What do you do?
Model: First, understand the underlying problem — is it really shape, or is it a missing variant the team needs? Three responses depending: (1) Legitimate variant: add a prop or new variant to the canonical button; ship through DS team review. (2) One-off marketing surface: allow a controlled escape hatch via composition (asChild, slot pattern), not a fork. (3) Genuinely different component: introduce a sibling primitive with shared tokens; don't pretend it's the same. Never silently fork — it dilutes the system. Document the decision in an ADR.
How do you ship a breaking change to a design system used by 30 product teams?
Model: Treat it like a public API. (1) Codemod first — write a jscodeshift / ts-morph codemod that migrates consumers automatically; ship the codemod with the breaking version. (2) Dual-publish — release the new major while old major remains supported for 1–2 quarters; deprecation warnings logged in dev. (3) Telemetry on usage — instrument which APIs are called; only break ones with confirmed adoption profile. (4) Migration guide + 1:1 office hours for high-impact teams. (5) Changelog with code examples, not just version notes. Reference: Stripe — migrating typed APIs · React 17 — “no new features” release for migration.

5.5 References

06State Strategy

"What state library should we use?" is the wrong question. "What kinds of state exist in our app, and where does each live?" is the right one.

6.1 The Four Kinds of State

KindLives inTools
Server stateCache reflecting a remote source of truthTanStack Query, RTK Query, Apollo, SWR, Relay
URL stateThe URL (query params, path, hash)Native router, TanStack Router (type-safe), nuqs
Form stateLocal to a form's lifecyclereact-hook-form, TanStack Form, Conform
Client UI stateApp-local ephemeral datauseState, useReducer, Zustand, Jotai, Redux Toolkit, XState
90% of "state management problems" disappear when you ask which of these four it is and put it in the right place.

6.2 Client-State Library Comparison

LibraryModelStrengthsWeakness
useState / useReducerLocalBuilt-in, zero depsNo sharing across distant components
ContextTree-scopedBuilt-in, simpleRe-renders all consumers; no slice selection
ZustandExternal store + hookTiny, fast, selectors, devtoolsHands-off — discipline required
JotaiAtomic primitivesGranular subscriptions, Suspense-nativeMany atoms = many references to track
Redux ToolkitFlux + slices + RTK QueryMature, devtools, time-travel, ecosystemVerbose; cognitive overhead for small apps
XStateStatechartsExplicit state, impossible-state-prevention, visualizerLearning curve; verbose
Valtio / MobXProxy/observableMutation-style ergonomicsMagic; reactivity tracking is implicit
Signals (proposal / Solid / Preact)Reactive primitiveO(1) updates, no diffingNot yet native in React

6.3 The Cache-Invalidation Question

Phil Karlton: "There are only two hard things in Computer Science: cache invalidation and naming things." TanStack Query won the FE space because it answered this:

  • Stale time — how long data is considered fresh; no refetch within this window.
  • Cache time / gcTime — how long unused data stays before garbage collection.
  • Refetch on window focus / reconnect / mount — automatic background refresh policies.
  • Optimistic updates with rollback on failure.
  • Query keys as cache keys — hierarchy enables targeted invalidation: ['user', userId, 'posts'].
  • Mutations + automatic invalidation — declarative dependencies.

6.4 Hard Questions

Pick: Zustand vs Jotai vs Redux Toolkit for a multi-tab collaborative product like Figma or Linear. Defend it.
Model: First clarify "state" — for Figma-like systems, the source of truth is a CRDT or OT engine that exists outside React. Whichever library you pick is a view layer adapter. For Linear-style: Jotai's granularity wins because thousands of tasks updating independently benefit from atomic subscription; Redux's selector model rerenders too aggressively without memoized selectors everywhere. For Figma-style: Zustand is often paired with a layer like Immer/Yjs — the React store mirrors slices of the CRDT for components to subscribe to. Avoid Redux Toolkit when update frequency > 60fps and you have thousands of subscribers — middleware overhead adds up. Discuss: useSyncExternalStore is the React 18+ hook designed for exactly this use case.
A team is using Redux for everything including server data. PRs are 500 lines for trivial changes. How do you propose change?
Model: Don't propose a rip-and-replace. Propose a layer split: introduce TanStack Query for new server-state needs; existing Redux slices that wrap remote data become candidates for migration. Migration order: read-heavy slices first (lowest risk), then mutations. Keep Redux for genuine client state (cross-page UI flags, undo/redo stacks, multi-step wizards). Track ratio of Redux LoC over time as a debt indicator. The pattern is "Redux for what only Redux is good at, Query for everything else." Cite: RTK Query official guidance reflects this split today.

6.5 References

07Data Layer & Caching

The data layer determines perceived performance more than any single rendering optimization. Network latency is your dominant cost.

7.1 REST vs GraphQL vs tRPC vs RPC

PatternBest whenWatch out for
REST + OpenAPIStable resource model; many consumers; CDN caching mattersOver-fetching; versioning sprawl
GraphQLMany consumers with different shape needs; federated backendsCaching complexity; N+1; payload-size bloat from defaults
tRPCMono-repo TS full-stack with single FE/BE ownerCouples FE to BE TS types — no decoupled evolution
gRPC-Web / ConnectPolyglot backends with strict schemasBrowser proxy required (gRPC); tooling friction
Server Actions (RSC)Single-app full-stack with Next.js / similarCoupling; observability gap; harder to test outside framework

7.2 The Cache Hierarchy

A modern FE has at least 4 caches on the path from server to user:

  1. Browser HTTP cache — governed by Cache-Control, ETag, Last-Modified.
  2. Service Worker cache — programmable via the Cache API and Workbox.
  3. In-memory client cache — TanStack Query / Apollo normalized cache.
  4. CDN cache — Cloudflare, Fastly, Akamai; tags, surrogate keys, soft-purge.

Lead-level understanding: each layer has different invalidation primitives. The challenge is consistent purge semantics across them. Stripe and Shopify use surrogate keys + tag-based purge to cascade invalidations.

7.3 HTTP Cache Headers — The Set That Matters

Cache-Control: public, max-age=31536000, immutable    # versioned static assets
Cache-Control: private, no-cache                       # HTML for authed pages
Cache-Control: public, s-maxage=60, stale-while-revalidate=600  # SWR pattern at CDN
ETag: "abc123"
Vary: Accept-Encoding, Accept-Language, Cookie

Reference: MDN HTTP caching · RFC 9111 · web.dev — SWR.

7.4 The N+1 Anti-pattern (Client Side)

// ❌ N+1: fires N requests sequentially
const users = await fetch('/api/users').then(r => r.json());
for (const u of users) {
  u.posts = await fetch(`/api/users/${u.id}/posts`).then(r => r.json());
}

// ✅ Batch + parallel
const users = await fetch('/api/users').then(r => r.json());
const postsByUser = await Promise.all(
  users.map(u => fetch(`/api/users/${u.id}/posts`).then(r => r.json()))
);
users.forEach((u, i) => (u.posts = postsByUser[i]));

// ✅✅ Batch endpoint (best)
const users = await fetch('/api/users?include=posts').then(r => r.json());

7.5 Hard Questions

Your product makes 40 API calls on the homepage. How do you cut that to 4?
Model: Diagnose first: open DevTools, look at the request waterfall. Categorize each call: (a) essential to first paint, (b) essential to interactive, (c) deferrable, (d) dead code calling stale endpoints. Tactics: (1) Batching — coalesce N user fetches into one. GraphQL solves this by design; with REST, build batch endpoints or use a BFF (Backends For Frontends). (2) BFF aggregation — a single FE-purpose endpoint that the server composes. Common at Netflix, Uber. (3) Prefetch on link hover or route guess. (4) HTTP/2 server push or 103 Early Hints for known critical assets. (5) Edge composition — fetch at CDN edge, return one HTML with data inlined. (6) RSC + Suspense streaming — fewer client fetches because data is rendered server-side. (7) Tail kill — anything below the fold should not be in the initial waterfall. (8) De-duplicate — Query/Apollo client dedup identical concurrent requests.
Explain optimistic updates with rollback in TanStack Query.
Model: In onMutate, cancel any in-flight refetch (queryClient.cancelQueries), snapshot the current cache value, then setQueryData with the optimistic value. Return the snapshot from onMutate as context. In onError, restore the snapshot via setQueryData. In onSettled, invalidate queries to re-sync with server truth. Edge cases: concurrent mutations (you may need a mutation queue), partial failure where the server applies some but not all changes (mutation idempotency / server-side compensating actions), stale snapshot if the user navigated away (cleanup in onMutate's cancelQueries). Reference: TanStack Query — optimistic updates.
Design a cache-invalidation strategy across CDN, service worker, and in-memory cache for a product page that changes price every 5 minutes.
Model: Layered TTLs with revalidation. CDN: s-maxage=300, stale-while-revalidate=3600 — serve stale while fetching fresh; price-update job purges surrogate key product-{id} on price change. Service worker: stale-while-revalidate strategy keyed on path. In-memory (Query): staleTime: 5 minutes, refetch on focus. Manual sync: on price-change event (WebSocket / SSE), client invalidates the specific query key, which propagates to UI. Discuss tag-based purge (Fastly Surrogate-Keys, Cloudflare Cache Tags Enterprise) — essential at scale. Mention: Fastly Surrogate-Key.

7.6 References

08Authentication & Identity

Auth is where security and UX collide. A Lead FE knows the protocols deeply enough to push back on bad backend designs.

8.1 Standards You Must Know

StandardWhat it isWhen
OAuth 2.0Delegated authorization frameworkThird-party app accesses user data on user's behalf
OIDC (OpenID Connect)Identity layer on top of OAuth 2.0; adds ID tokensLogin / SSO
OAuth 2.1Consolidation of best practices; PKCE mandatoryModern default
SAMLOlder enterprise SSO via signed XMLEnterprise B2B
WebAuthn / PasskeysPublic-key crypto in the browser; phishing-proofModern auth without passwords
FedCMBrowser-native federated identity (Chrome+)Replacing third-party cookies for SSO
SCIMUser provisioning across SaaSEnterprise admin flows
OPA / Cedar / OpenFGAAuthorization decision enginesFine-grained authz

8.2 The OAuth 2.1 Flow (Authorization Code + PKCE)

  1. Client generates a random code_verifier, derives code_challenge = SHA256(verifier).
  2. Redirect to /authorize?response_type=code&client_id&redirect_uri&scope&state&code_challenge&code_challenge_method=S256.
  3. User authenticates; provider redirects to redirect_uri?code=xxx&state=yyy.
  4. Client POSTs code + code_verifier to /token; receives access_token, id_token (OIDC), maybe refresh_token.
  5. Client calls APIs with Authorization: Bearer <access_token>.

PKCE makes the flow safe for public clients (SPAs, mobile). Reference: OAuth 2.1 draft · OIDC spec · oauth.net/2.1

8.3 Token Storage — The Hard Decisions

StorageRiskVerdict
localStorageXSS reads it instantly. Avoid for access tokens.❌ for sensitive tokens
sessionStorageSame XSS risk; cleared per tab❌ for sensitive tokens
HttpOnly cookieJS can't read it. CSRF risk — mitigate with SameSite=Lax + CSRF tokens for mutating requests✅ for session
In-memory onlyLost on reload; requires silent re-auth via refresh cookie✅ pattern: short-lived access in memory + long-lived refresh in HttpOnly cookie
Web WorkerJS can hold token in worker scope; harder for XSS to exfiltrate⚠️ defense in depth, not silver bullet
The 2025+ consensus: backend-for-frontend (BFF) pattern owns tokens server-side; browser holds only a session cookie. Auth0, Okta, and OWASP recommend this. Reference: OAuth 2.0 for Browser-Based Apps (BCP).

8.4 WebAuthn / Passkeys — The Future

Passkeys are FIDO2 credentials synced via platform cloud (iCloud Keychain, Google Password Manager, 1Password). UX: tap fingerprint, in. Security: private key never leaves device, public key on server; phishing-proof because the key is bound to the origin.

// Register a passkey
const credential = await navigator.credentials.create({
  publicKey: {
    challenge: serverChallenge,       // server-provided random
    rp: { id: 'example.com', name: 'Example' },
    user: { id: userId, name: email, displayName: name },
    pubKeyCredParams: [{ alg: -7, type: 'public-key' }],
    authenticatorSelection: { residentKey: 'required', userVerification: 'preferred' },
  }
});
// Send credential.response to server for verification

Reference: passkeys.dev · WebAuthn guide · W3C WebAuthn L3

8.5 Authorization (AuthZ) — Not Auth (AuthN)

Patterns:

  • RBAC — Role-Based Access Control. Roles → permissions. Simple, scales poorly with edge cases.
  • ABAC — Attribute-Based. Decisions on user/resource attributes. Flexible.
  • ReBAC — Relationship-Based. Google Zanzibar paper; OpenFGA, SpiceDB, Permify. Best for "user can edit doc because they're in group that owns folder."

Reference: Google Zanzibar paper · OpenFGA

8.6 Hard Questions

Walk me through OAuth 2.1 with PKCE end-to-end. Now tell me what an attacker can do if PKCE is missing.
Model: Without PKCE, the authorization code is the only secret between authorize and token endpoints. An attacker who intercepts the redirect (malicious app on same device, mis-registered redirect URI, network mitm before TLS termination at the IDP) can exchange the code for tokens. PKCE binds the code to a verifier generated only by the legitimate client; intercepting the code is useless without the verifier (which never leaves the client). Discuss why state param protects against CSRF in the redirect, while nonce in OIDC protects against ID token replay.
A backend team says "just put the JWT in localStorage, we'll trust the browser." How do you respond?
Model: Frame it as a threat model. XSS exists — every dependency you import (including transitively through CDN scripts) is a potential XSS source. A JWT in localStorage is exfiltrated by any XSS in one fetch. HttpOnly cookies are not readable by JS at all. The "we trust the browser" framing is wrong — the browser is your hostile execution environment in security thinking. Propose BFF or HttpOnly cookie with SameSite=Lax + CSRF protection. Reference OWASP cheat sheet and recent breaches (LastPass 2022, CircleCI 2023 — tokens were the vector).
Design SSO for an internal platform shared across 20 product teams.
Model: Single OIDC IDP (Okta, Auth0, internal Keycloak); platform shell handles login + token refresh; per-team apps consume identity via signed JWT exchanged at the BFF layer for service-scoped tokens (token exchange RFC 8693). Discuss: silent re-auth via iframe is deprecated; FedCM is the modern path. Cross-subdomain cookies for shared session. RBAC roles centrally managed; ABAC for fine-grained per-app authorization. Audit log every token exchange. Session timeout policy per product (sensitive admin tools: 15 min idle; consumer surfaces: 30 days).

8.7 References

09Routing

Routing is the public API of your app. URLs are forever; design them like they will be.

9.1 URL Design Principles

  • Resource-oriented nouns: /users/:id/projects/:slug, not /getUserProject.
  • Hackable — users can guess parent routes by truncating segments.
  • Stable — set up redirects for any breaking change. Search engines and bookmarks live forever.
  • Sharable — state critical to reproducing the view is in the URL (filters, sort, page, tab).
  • Localizable — locale either in subdomain (en.example.com), path (/en/products), or via Accept-Language. Decide consciously.
  • Type-safe at the boundary — runtime validate params (Zod) at the loader.

9.2 Router Landscape

RouterBest for
React Router v7 (merged with Remix)Modern data-router; framework or library mode; loaders/actions; SSR or SPA
Next.js App RouterRSC-native; file-system routing; layouts; parallel + intercepting routes
TanStack RouterFull type-safety from path params to search params; framework-agnostic
WouterTiny — for embed widgets, micro-FEs
Reach Router / Hash routerLegacy; avoid for new work

9.3 Next.js App Router — The Patterns to Know

  • Nested layouts — shared shell across child routes; preserved on navigation.
  • Loading.js / Suspense — instant loading UI while data streams.
  • Error.js — per-segment error boundary.
  • Parallel routes — render multiple slots simultaneously (dashboard with sidebar + content).
  • Intercepting routes — modal overlays that survive refresh (Instagram-style photo modal).
  • Route groups — folder-as-segment escape: (marketing) doesn't add a URL segment.
  • Dynamic segments + generateStaticParams — SSG for known paths, fallback for unknown.

9.4 Hard Questions

A product team wants every filter to be a query param. Search params now look like ?status=open&assignee=alice&sort=-created&cursor=xyz. How do you keep this maintainable?
Model: Treat URL search params as typed state. (1) Single source of truth — derive UI from URL, mutate URL on user action. (2) Schema layer — Zod schema validates and parses; TanStack Router does this natively. (3) Helpers for serialization (arrays, dates) — pick a stable encoding (e.g., comma-separated for arrays, ISO-8601 for dates). (4) Default-collapse — omit params equal to defaults from the URL. (5) Param routing — avoid ?tab=billing if a path segment is more semantic. (6) Bookmarkable + back-button correct: every state change updates history meaningfully. Reference: nuqs for ergonomic typed search params.
Your app shows a modal at /photo/123 that overlays the feed. Refresh should still show the modal but with feed underneath. How?
Model: Next.js App Router has parallel + intercepting routes for this exact pattern. @modal slot in the layout; (.)photo/[id] intercepting route renders the modal when navigating from the feed (client-side); when the URL is loaded fresh, the regular /photo/[id] route renders a full page. Same URL, two render trees depending on entry. Reference: Next.js intercepting routes.

9.5 References

10Forms & Validation

Forms are where 80% of conversion lives. Lead candidates know forms cold.

10.1 Library Picks (2026)

LibraryUse
react-hook-form + Zod (resolver)The de-facto default. Uncontrolled-by-default, minimal re-renders, schema validation.
TanStack FormFramework-agnostic, type-safe end-to-end; rising.
ConformProgressive enhancement; works with native forms + RSC server actions; Remix/Next compatible.
FormikLegacy; superseded for new work.

10.2 Validation Schemas

  • Zod — most popular; great DX; chained API.
  • Valibot — tree-shakable, smaller bundle (a fraction of Zod).
  • ArkType — fastest at runtime; TS-syntax inspired DSL.
  • Standard Schema — emerging interop spec so libraries can target multiple validators.

10.3 The Hard Form Problems

  • Async validation — username availability, debounced calls, race condition handling (latest-only wins).
  • Cross-field rules — confirm password matches, end date after start date.
  • Conditional fields — schema that changes based on prior selections; z.discriminatedUnion.
  • Multi-step wizards — partial submit + draft persistence; URL state per step.
  • Server-returned validation errors — surface per field with translated messages; 422 with field map.
  • Optimistic + offline submission — local-first persist; sync queue; conflict resolution.
  • Accessible errorsaria-describedby, aria-invalid, error list with focus management, screen reader announcement.

10.4 Hard Questions

Design a multi-page checkout with validation, progressive enhancement, and analytics. Walk me through the architecture.
Model: URL-driven steps (/checkout/shipping, /checkout/payment, /checkout/review). Each step owns its schema; previous-step state persisted server-side (cart record). Progressive enhancement: each step is a native <form action> with server action; JS-on adds inline validation + optimistic UX. Conform or Remix-style data router fits. Validation runs both client-side (DX) and server-side (security — never trust client). Analytics: per-step funnel events, error events with field name, abandonment events on unmount. Accessibility: focus to first error on validation fail; announce errors via aria-live. PCI: tokenize card via iframe (Stripe Elements) so card data never touches your server. Recovery: pre-fill from session on return; clear on success.
You have a complex form (50+ fields) and re-renders are killing performance. Diagnose.
Model: First measure — React Profiler, find which subscriptions trigger. Common causes: (1) controlled inputs feeding a single state object — every keystroke re-renders the whole form. Fix: switch to react-hook-form (uncontrolled subscriptions per field). (2) Context wrapping form data — splits or selectors needed. (3) Heavy computed values not memoized. (4) Schema parse on every keystroke — debounce or move to onBlur validation mode. (5) Inline functions in child props defeating React.memo. (6) Consider field-level Suspense for async validation. After fix, set perf budget: typing latency < 16ms p95.

11Internationalization (i18n & l10n)

i18n done badly is impossible to fix later. Done well, it's invisible.

11.1 The Vocabulary

TermMeaning
i18n (Internationalization)Making the app capable of supporting multiple locales
l10n (Localization)Actual translation/adaptation for a specific locale
g11n (Globalization)i18n + l10n + cultural adaptation
ICU MessageFormatStandard for plurals, gender, select, nested arguments
BCP 47Language tag spec (en-US, zh-Hant-HK)
CLDRUnicode Common Locale Data Repository — formats, plurals, calendars
RTLRight-to-left scripts: Arabic, Hebrew, Persian, Urdu

11.2 The Common Mistakes

  • String concatenation"You have " + n + " items" breaks for word order in other languages. Use ICU MessageFormat.
  • Hard-coded plural rules — many languages have more than 2 plural forms (Arabic has 6, Russian 4). Use CLDR plural rules.
  • Date / number formatting with manual code — use Intl.DateTimeFormat, Intl.NumberFormat, Intl.RelativeTimeFormat, Intl.ListFormat.
  • Pixel-based layouts — Japanese text is shorter, German much longer; layouts must flex.
  • Forgetting RTL — use logical CSS properties (margin-inline-start, padding-block-end).
  • Sortable strings — use Intl.Collator, never String.prototype.localeCompare without options.
  • String IDs as English — use stable hashes/IDs so source English can change without breaking IDs in translation memory.

11.3 Modern Tools

11.4 Hard Questions

Your product launched in English. Marketing wants Arabic and Japanese in 8 weeks. What's your plan?
Model: Audit first — find every hard-coded string (use ESLint plugin no-literal-strings); audit every date/number/currency format (manual code is the killer); audit every layout that won't flex; identify RTL deltas. Set up TMS pipeline: extract → upload to Crowdin → translate → download → bundle. Pick library (Lingui or react-intl). Implement RTL via dir="rtl" on html + logical CSS properties + a Tailwind plugin if applicable. Test process: pseudo-localize to expand strings to 130% (catch overflows); visual-regression per locale in Storybook. Critical path: get the foundation right in 2 weeks (extraction + library + RTL); translation in parallel; QA in the last 2 weeks. Reference: Smashing — i18n in React · RTL Styling 101.

12Testing Pyramid & Quality Strategy

A Lead designs the test strategy — not just writes tests. The shape of the test portfolio is a leadership artifact.

12.1 The Modern Test Portfolio (post-Trophy / post-Pyramid)

Kent C. Dodds proposed the "Testing Trophy" — emphasizing integration over unit. Honeycomb / Spotify use a different shape. The truth: shape depends on product. Below is a sane default for a modern web product.

LayerToolsWhat it covers~%
Static analysisTypeScript, ESLint, Biome, SemgrepType errors, lint rules, security patterns
UnitVitest, JestPure functions, hooks (with renderHook), reducers, utils30%
Component / IntegrationReact Testing Library + MSWComponent behaviour with realistic data fetching50%
Visual regressionChromatic, Playwright snapshots, PercyPixel/structural changes per Storybook story
Contract testsPact, MSW handlers as contractFE vs BE schema compatibility
E2EPlaywright, CypressCritical user flows on real browser15%
Accessibilityaxe-core, Pa11y, manual SR testingWCAG conformance
PerformanceLighthouse CI, WebPageTest API, CalibrePerf budgets enforced on PR
Load / chaosk6, Gatling, Toxiproxy (network chaos)Behaviour under adverse conditions5%

12.2 The Test-Strategy Question

Decisions a Lead makes explicitly:

  • What flakiness rate is acceptable? Typical target: < 1% per E2E. Above that, automation becomes a tax.
  • Who fixes flakes? "Last green pipeline" owner or a dedicated quality engineer.
  • What's mocked vs real? Default: mock network at MSW boundary, run real timers, real fetch. Mock 3rd-party SDKs at module boundary.
  • What's covered by E2E vs integration? Rule: E2E for cross-team contracts (auth → product → checkout); integration for within-team.
  • How is test data managed? Test factories (e.g., fishery); avoid hand-rolling fixtures.
  • How are flaky tests quarantined? Auto-quarantine after N flakes; assign ticket to owner; remove from blocking after fix.

12.3 Hard Questions

Your E2E suite takes 90 minutes and is 30% flaky. The team is bypassing it. Plan.
Model: Frame as flakiness-first, then speed. (1) Measure flakes — track per-test failure rate over time; the top 10 flakes are usually 80% of pain. (2) Categorize — race conditions (use Playwright's auto-waiting, never sleep), env coupling (test database not isolated), 3rd-party (mock vendor SDKs at the network layer with MSW). (3) Quarantine the worst flakes; demand owners fix in 1 sprint or delete. (4) Speed: Playwright sharding, fixture reuse, parallel workers, headless on CI; consider Playwright's "trace on retry" for debugging. (5) Shrink scope — many E2E tests are integration tests in disguise; rewrite as RTL + MSW. Lead position: E2E is a backstop for critical flows, not a primary test layer. Target: < 15 min, < 1% flake, 8–15 tests on golden path only. Reference: Playwright best practices · RTL guiding principles.
A test "passes locally, fails in CI." Diagnose systemically.
Model: Top causes by frequency: (1) Time zone — CI runs UTC, dev runs local; mock Date globally. (2) Locale — number / date formatting differs; pin process.env.LANG. (3) Test isolation — module mocks leaking; resetMocks + restoreMocks per test. (4) Order dependency — Vitest's --shuffle catches; same with Jest. (5) CI slowness — race condition only manifests under load. (6) Snapshot diffs for environment-dependent output (file paths, port numbers). (7) Network — flake from real network calls; MSW everywhere. Investigate by capturing CI trace artifact; reproduce by running the same Docker image locally.

12.4 References

13Performance Engineering

Lead-level perf is not "make Lighthouse green." It's "set budgets, instrument them, defend them, and explain the trade-offs."

13.1 Core Web Vitals (2026 state)

MetricWhatGood (p75)Poor
LCPLargest contentful paint< 2.5s> 4.0s
INPInteraction to Next Paint (replaces FID March 2024)< 200ms> 500ms
CLSCumulative layout shift< 0.1> 0.25
FCPFirst contentful paint< 1.8s> 3.0s
TTFBTime to first byte< 0.8s> 1.8s
TBT (lab only)Total blocking time< 200ms> 600ms

13.2 Performance Budgets

A Lead defines budgets per route, not per app:

# perf-budget.yaml
routes:
  /:
    js: 170kb
    css: 30kb
    lcp_p75: 2.0s
    inp_p75: 150ms
  /product/[id]:
    js: 220kb
    images: 600kb
    lcp_p75: 2.5s
  /admin/*:
    js: 500kb        # power user, larger budget acceptable
    lcp_p75: 4.0s

Enforce via Lighthouse CI, size-limit, bundlewatch, or Calibre on every PR; block merge if violated.

13.3 The Perf Diagnostic Playbook

  1. Capture: WebPageTest from a representative location with throttled connection (Slow 4G, Moto G Power); record filmstrip + waterfall + Lighthouse trace.
  2. Classify: which CWV is failing? LCP → asset on critical path. INP → main-thread work. CLS → layout instability.
  3. Diagnose: open trace in DevTools Performance; look at long tasks, layout shift regions, LCP element selection.
  4. Hypothesize: one change, predict impact.
  5. Implement & measure: A/B in production via feature flag, or controlled lab measurement at minimum.
  6. Lock it in: add a budget assertion so regression breaks CI.

13.4 LCP Playbook

  • Identify LCP element (DevTools surface; PerformanceObserver in code).
  • If image: fetchpriority="high", AVIF/WebP, responsive srcset, preload hint, no lazy loading for above-fold.
  • If text: font-display: swap; preload critical fonts; self-host (Google Fonts CDN adds DNS + TLS hops).
  • Reduce render-blocking CSS: inline critical, async load rest.
  • Defer non-critical JS; code-split aggressively.
  • Improve TTFB: edge SSR or static; cache HTML at CDN.
  • 103 Early Hints for known critical resources.

13.5 INP Playbook

  • Find long tasks > 50ms via Long Animation Frames API (replaces Long Tasks).
  • Yield to the main thread: scheduler.yield(), requestIdleCallback, React's useTransition.
  • Virtualize long lists (TanStack Virtual, react-window).
  • Memoize expensive recomputations; React Compiler does this automatically.
  • Move heavy work to Web Workers (Comlink for ergonomic RPC).
  • Avoid synchronous reflow in event handlers (read all then write all).

13.6 CLS Playbook

  • Always set width/height on images and embeds OR aspect-ratio.
  • Reserve space for ads, banners, dynamically inserted content.
  • Animate transform/opacity only; never width/height/top/left for animations.
  • Font swap: size-adjust, ascent-override on @font-face; or use font-display: optional.
  • Avoid inserting DOM above existing content unless triggered by user interaction (which excludes from CLS).

13.7 Real User Monitoring (RUM)

  • Use the web-vitals JS library to capture CWV in production.
  • Send to a backend: SpeedCurve, Calibre, Datadog RUM, Sentry Performance, Vercel Speed Insights, your own.
  • Slice by route, device, region, connection, build hash — find where regression lives.
  • Alert on p75 regression of any CWV by > 10% over 24h.

13.8 Hard Questions

Your LCP p75 went from 2.1s to 3.8s overnight. No deploy in 24h. Investigate.
Model: Open RUM dashboard; slice by version, region, device, browser. If only one region: CDN or upstream issue (status page check). If only one device class: rendering regression — but no deploy rules out FE. Common causes: (a) third-party script vendor pushed an update (Segment, Optimizely, ad SDK) — check vendor change logs and unblock by removing/deferring the SDK to confirm; (b) backend latency increased — TTFB regression visible in same RUM; (c) traffic shift to slower geos. Roll back third-party SDK first if suspected. Long-term: lock third-party scripts via tag manager versioning; load via self-host proxy with integrity checks; budget third-party impact explicitly. Reference: web.dev LCP.
Why is the React Compiler significant for INP?
Model: Manual useMemo/useCallback are often missing where they'd help and present where they hurt (memoization itself has cost). React Compiler analyzes component code at build time and inserts memoization wherever it provably reduces re-renders without changing semantics. Result: fewer wasted renders → less main-thread work → better INP. It also enables more aggressive optimization in future React versions (selective hydration improvements, parallel rendering). Discuss: it's not a silver bullet for INP — heavy synchronous computations still need yielding, virtualization, workers. Reference: React Compiler docs.
Discuss the performance trade-offs of CSR vs SSR vs SSG vs RSC for an e-commerce product page.
Model: CSR — fastest TTFB (static shell) but blank LCP until JS + data load; bad for SEO. SSR — better LCP and SEO but full HTML re-renders each request; server cost scales with traffic; cache at CDN with surrogate keys helps. SSG — best LCP (pure HTML from CDN) but build time scales with catalog size; ISR mitigates by lazy-regenerating on demand. RSC — server-rendered tree with client islands; smaller JS bundle than SSR (server-only components ship no JS); streams data progressively. For e-commerce: most teams pick SSG + ISR or RSC streaming. Discuss cache invalidation on price/inventory changes (tag-based purge), personalization at the edge (split: static shell + personalized fragment), and analytics for which strategy actually moves conversion. Cite: Shopify Hydrogen (Remix-based, edge SSR), Amazon (heavy CSR for catalog, SSR for PDP), Walmart (Edge SSR).

13.9 References

14Accessibility (a11y)

Accessibility is a competitive advantage hiding behind a compliance label. Lead candidates treat WCAG as a floor, not a ceiling.

14.1 The Standards Landscape (2025+)

StandardScope
WCAG 2.2 (Oct 2023)Current. 9 new criteria over 2.1 (focus appearance, dragging, target size 24×24, accessible authentication, etc.).
WCAG 3 (Silver)Draft. Outcome-scored, broader scope (cognitive, mobile, AR/VR).
EAA (European Accessibility Act)Enforced June 28, 2025. Applies to private-sector digital products sold in EU.
ADA Title III (US)Court interpretation aligns with WCAG 2.1/2.2 AA.
Section 508 (US federal)Procurement; aligns with WCAG 2.0 AA via Revised 508.
EN 301 549EU harmonized standard incorporating WCAG.
AODA (Ontario)WCAG 2.0 AA mandated for large orgs.

14.2 The Four Principles (POUR)

  1. Perceivable — text alternatives, captions, contrast ≥ 4.5:1 (normal text), structure conveyable in multiple ways.
  2. Operable — full keyboard, no time traps, no flashing > 3/s, skip links, focus visible.
  3. Understandable — readable language, predictable navigation, error identification and suggestion.
  4. Robust — works with current and future AT; valid HTML, ARIA used correctly.

14.3 ARIA — The Five Rules

  1. Don't use ARIA — use semantic HTML when it exists.
  2. Don't change native semantics — never put role="button" on an h1.
  3. All interactive ARIA must be keyboard-accessible.
  4. Don't use role="presentation" or aria-hidden="true" on focusable elements.
  5. Every interactive element needs an accessible name.

Reference: W3C — Using ARIA · ARIA Authoring Practices Guide

14.4 Focus Management — The Hard Part

  • Route changes in SPAs — focus a heading or a skip-link target; announce via live region.
  • Modals — trap focus inside; restore to triggering element on close; use inert attribute on background.
  • Drag and drop — provide a keyboard alternative (arrow keys + space).
  • Toasts / notificationsrole="status" for polite, role="alert" for assertive; don't steal focus.
  • Async contentaria-live="polite" regions; aria-busy="true" while loading.
  • Focus visible — never outline: none without a replacement; use :focus-visible for keyboard-only rings.

14.5 Testing Approach

LayerToolCatches
Static / unitjsx-a11y ESLint, axe-core in RTL testsMissing alt, contrast (sometimes), misuse of ARIA
Story-level@storybook/addon-a11yPer-component automated audit
E2Eaxe-playwrightPage-level axe scans in critical flows
Manual keyboardYourself, 5 minutes per critical flowFocus traps, missing skip-links, broken Esc handling
Manual screen readerNVDA (Windows free), VoiceOver (Mac built-in), JAWS (enterprise)Reading order, announcement quality, ARIA misuse
User testingFable Tech Labs, Applause, internal a11y guildReal-world friction
Automated tools catch ~30–40% of WCAG issues (Deque study). The rest require human judgment. Reference: Deque accuracy study.

14.6 Hard Questions

Build an accessible custom Select component from scratch — what behaviour and ARIA do you need?
Model: Native <select> if you can — describe the 47 platform-specific behaviors you'd otherwise re-implement (Android picker, iOS wheel, Windows dropdown). If you must custom: ARIA combobox pattern (per APG 1.2): role="combobox" on the input, aria-expanded, aria-controls="listbox-id", aria-activedescendant pointing to highlighted option. Listbox: role="listbox" + role="option" children with aria-selected. Keyboard: Up/Down navigates; Home/End jump; Type-ahead matches; Enter selects; Esc closes restoring focus. Touch: full-screen drawer on mobile is acceptable. Better: adopt Radix Select or React Aria Select — they have shipped these 47 behaviors. Reference: APG Combobox pattern.
A designer hands you a UI with light-gray placeholder text and an icon-only "delete" button. Walk me through what you push back on.
Model: (1) Placeholder contrast — placeholders need ≥ 4.5:1 against the input background AND must not replace the label. Push for a visible label always (placeholders disappear on type, confuse cognitive impairment users, and bypass autofill). (2) Icon-only button — needs accessible name. Provide via aria-label="Delete" AND a visible tooltip on hover/focus. Mention WCAG 2.5.5 (Target Size) — 24×24 minimum for WCAG 2.2, 44×44 for AAA. (3) Destructive action — confirmation pattern (dialog or undo toast); never a single click for irreversible. (4) Discuss the color choice — is delete signaled only by red? Add a label too (color-only conveying is a WCAG fail). Frame as collaboration, not policing; offer alternatives.

14.7 References

15Security

A Lead FE thinks like an attacker. Every input is hostile until proven otherwise.

15.1 OWASP Top 10 (2021) — Frontend Lens

RiskFrontend exposureMitigation
A01 Broken Access ControlUI hides admin nav but no server enforcementServer always re-validates; treat client as untrusted
A02 Cryptographic FailuresJWT in localStorage, weak hashing in clientHttpOnly cookies, no client-side crypto for secrets
A03 Injection (incl. XSS)Untrusted HTML, href={input}, eval, innerHTMLDefault React escape, DOMPurify, Trusted Types, CSP
A04 Insecure DesignMissing threat modeling on new featuresSTRIDE review per design doc
A05 Security MisconfigurationMissing CSP, source maps in prod, exposed envHeaders audit, env hygiene, source map upload not serve
A06 Vulnerable ComponentsStale npm depsSnyk/Socket/Dependabot, lockfile review, SBOM
A07 ID & Auth FailuresToken storage, session managementBFF pattern, short-lived access tokens, MFA
A08 SW & Data Integrity FailuresCDN script tampering, supply-chain attacksSRI hashes, pinned versions, Socket.dev
A09 Logging & Monitoring FailuresNo FE error tracking, no audit logSentry / Datadog, redact PII
A10 SSRFMostly server; relevant if FE proxies arbitrary URLsURL allowlist

15.2 XSS — The Three Types

  • Stored — payload saved server-side, served to others. Most dangerous.
  • Reflected — payload in URL/query, executed on render.
  • DOM-based — client JS writes attacker input to DOM unsanitized.

React escapes string interpolation by default. The remaining holes:

  • dangerouslySetInnerHTML — use DOMPurify or html-react-parser with allowlist.
  • href={userInput}javascript: URI is XSS. Allowlist protocols (https, http, mailto, tel).
  • style={userInput} — CSS injection (data exfiltration via background-image: url(...)).
  • Third-party libraries that document.write or set innerHTML internally.

15.3 Content Security Policy (CSP)

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{random}' https://www.googletagmanager.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: blob: https:;
  font-src 'self' data:;
  connect-src 'self' https://api.example.com https://*.sentry.io;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
  upgrade-insecure-requests;
  report-uri /csp-report;
  report-to default;

Nonce-based CSP (random nonce per request, applied to legitimate inline scripts) is the modern default. 'unsafe-inline' for scripts is a deal-breaker — use nonces or hashes.

Reference: web.dev — Strict CSP · content-security-policy.com

15.4 Trusted Types (the modern XSS firewall)

A browser API that prevents passing strings to DOM XSS sinks (innerHTML, document.write) unless wrapped in a policy-approved type. Google deployed it to reduce XSS to near-zero on their consumer products.

Content-Security-Policy: require-trusted-types-for 'script'; trusted-types my-policy

Reference: web.dev — Trusted Types · W3C Trusted Types spec

15.5 Security Headers (the full set)

HeaderWhat
Content-Security-PolicyAllowlist of sources for each resource type
Strict-Transport-SecurityForce HTTPS; max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniffPrevent MIME confusion attacks
X-Frame-Options: DENYClickjacking defense (deprecated in favor of CSP frame-ancestors)
Referrer-Policy: strict-origin-when-cross-originLimit referer leakage
Permissions-PolicyRestrict camera, mic, geolocation, payment, etc.
Cross-Origin-Opener-Policy / COEPRequired for SharedArrayBuffer; isolates browsing context
Cross-Origin-Resource-PolicyRestrict who can load your resources cross-origin

Audit: securityheaders.com · Google CSP Evaluator

15.6 Supply Chain Security

  • Lockfile hygiene — never auto-merge dependency PRs without review.
  • Snyk / Socket.dev / GitHub Dependabot — scan for known CVEs and malicious packages.
  • SBOM (Software Bill of Materials) — CycloneDX or SPDX format; CISA mandates for federal contracts.
  • Pinned versions — no ^ or ~ for production deps in lockfile.
  • Subresource Integrity (SRI) for any CDN-loaded script.
  • npm install discipline — review postinstall scripts; consider --ignore-scripts.
Recent supply-chain attacks: ua-parser-js (2021), node-ipc (2022 — protestware), event-stream (2018), polyfill.io (2024 — CDN takeover). Pattern: malicious code in transitive deps. Treat node_modules as untrusted code.

15.7 Hard Questions

An attacker can run arbitrary JS in your origin once. What can they steal, and how do you defend against each?
Model: (1) Tokens in localStorage — HttpOnly cookies prevent. (2) Same-origin XHR data — credentials sent automatically; only defense is short-lived sessions + step-up auth for sensitive actions. (3) Form data via injected handlers — Trusted Types prevent injection in the first place. (4) Cookies via document.cookie — HttpOnly. (5) Sensitive innerText scraping — minimize sensitive data shown in DOM; lazy-fetch on user action. (6) Camera/mic/clipboard — Permissions-Policy restricts; user permission re-prompt for sensitive features. (7) Persistence via service worker registration — restrict via CSP and explicit allowlist. Defense in depth: CSP + Trusted Types + HttpOnly cookies + CSRF tokens + SRI + minimal third parties + Permissions-Policy.
Walk me through threat-modeling a new "share via link" feature.
Model: Apply STRIDE. Spoofing: can link be forged to impersonate? Sign with HMAC. Tampering: can recipient modify permissions in the URL? Treat URL as opaque token, decode server-side, never trust URL claims. Repudiation: log who created the link and who used it. Info disclosure: link in browser history, email forwards, screenshots — assume leakage. Expire links; require auth for sensitive resources even via link. DoS: rate-limit link creation; rate-limit link usage from suspicious patterns. Elevation: ensure link scope cannot escalate (no "share document" that accidentally shares folder). Privacy: don't put PII in URL; log retention policy. Compliance: GDPR right-to-delete should kill outstanding links. Document in ADR.

15.8 References

16Observability

If it's not measured, it doesn't exist. Frontend observability is harder than backend because you can't put a debugger on the user's browser.

16.1 The Three Pillars (+ Two)

PillarWhatTools
LogsDiscrete events; "user clicked checkout"console (dev), telemetry SDK in prod
MetricsAggregate numbers; "p95 LCP this hour"web-vitals, Datadog, Prometheus exporters
TracesCross-service request path; "this click took 800ms — which service?"OpenTelemetry JS, W3C Trace Context
ErrorsExceptions + breadcrumbsSentry, Bugsnag, Rollbar, Datadog
Session replayReconstructed user sessionsLogRocket, Sentry Replay, FullStory, Hotjar

16.2 Error Tracking — Production-Grade

  • Source map upload on every deploy; never serve source maps publicly.
  • Release tagging — every error tagged with build hash + version; regression detection automated.
  • User context — anonymized user id, plan, locale, but redact PII.
  • Breadcrumbs — last N navigations, network calls, console messages.
  • Error boundaries in React at route + feature granularity with fallback UI + automatic report.
  • Unhandled rejection + window.onerror capture for what bypasses boundaries.
  • Sample rate — for high-traffic apps; bias toward keeping rare errors.
  • Alerting — new error type within 24h → on-call ping; spike of existing error > threshold → ping.

16.3 Distributed Tracing on the Client

OpenTelemetry JS lets you create spans on the client and propagate W3C traceparent headers to your backend. Result: a single trace from user click to database query.

// Client-side span
const tracer = trace.getTracer('frontend');
const span = tracer.startSpan('checkout-submit');
try {
  await fetch('/api/checkout', {
    method: 'POST',
    headers: { /* OpenTelemetry auto-injects traceparent */ },
    body: JSON.stringify(data),
  });
} finally {
  span.end();
}

Reference: OpenTelemetry JS · W3C Trace Context

16.4 Analytics & Product Telemetry

  • Schema-first events — typed event schema (Avro / JSON Schema); contract enforced in code.
  • Server-side or client-side? Client = user behaviour, latency, errors. Server = revenue, authoritative state. Both for accuracy.
  • Consent & privacy — IAB TCF v2.2, OneTrust, native consent banner; honor consent flags before any tracking.
  • Avoid third-party trackers on critical path — load async, after LCP; ideally proxy server-side.

16.5 Hard Questions

Users report "the app is slow today." You see no error spike. Where do you look?
Model: (1) RUM: is p75 LCP/INP regressing? Slice by version, region, device, network. (2) Synthetic monitoring: did your scheduled WebPageTest run show changes? (3) Backend: is API p95 latency up? Cross-check with trace context. (4) Third-party: any vendor SDK in waterfall taking longer than yesterday? Check their status pages. (5) CDN: hit rate down? Origin egress up? (6) Browser-specific: any new Chrome/Safari release rolled out causing regressions? (7) Internet-wide: BGP issue, Cloudflare incident. Investigate with hypothesis + measurement, not gut. Document the root cause. Build dashboards to detect this faster next time — alert on RUM regression auto-paged.

16.6 References

17CI/CD & Release Engineering

"How often can you ship safely?" is a leadership metric. The answer should be "any time we want, and we have."

17.1 Release Strategies

StrategyHowWhen
Blue-GreenTwo identical envs; swap traffic; instant rollbackDatabase-schema-stable releases
CanaryRoute N% of users to new version; ramp upRisky changes; gradual confidence
RollingReplace instances one at a timeStateless services; common for k8s
Feature FlagsCode in prod, off by default; toggle per userTrunk-based dev; A/B testing
Branch-by-AbstractionToggle between old and new implementation behind an interfaceLarge refactors
Dark LaunchSend traffic to new code path, discard response, measureValidating new backend without UX change

17.2 Feature Flags — Done Right

  • Use a real flag platform: LaunchDarkly, Split, Unleash, ConfigCat, GrowthBook (OSS), Statsig.
  • Three flag types: release (short-lived, deleted after rollout), experiment (A/B with metrics), permission (long-lived; access control).
  • Maintain a flag inventory with TTL; auto-create cleanup tickets when a release flag passes 30 days.
  • Default state should be safe (off).
  • Server-side resolution prevents flicker; client-side allows fast UI swap.
  • Test both branches in CI.

17.3 The Deployment Pipeline (Lead-quality)

Step 1

PR opened

Lint, type-check, unit tests, build, bundle-size budget, security scan. Preview deploy to ephemeral URL.

Step 2

Merge to main

Full E2E suite on built artifact. Visual regression. Tag artifact with commit SHA.

Step 3

Auto-deploy to staging

Smoke tests; perf budget check against staging baseline; accessibility scan.

Step 4

Canary to production (1–5%)

Watch error rate, CWV, business metrics for 15–30 minutes.

Step 5

Ramp to 100%

Or rollback automatically on alert. Tag release; post in #releases.

Step 6

Post-deploy

Source maps uploaded; SBOM published; release notes auto-generated from conventional commits.

17.4 Hard Questions

Define and defend a deployment frequency target for a 30-engineer FE team.
Model: Aim for at least one deploy per engineer per day on average (DORA "elite" performers deploy on demand multiple times per day). Justification: small batches reduce risk (smaller blast radius per change), faster feedback loop (engineers learn from production behavior within hours not weeks), better rollback resolution. Prerequisites: trunk-based development, sub-15-minute CI, automated rollback, feature flags. Anti-pattern: "release train every 2 weeks" — increases blast radius and reduces accountability per change. Reference DORA's "Accelerate" book findings.

17.5 References

18Deployment, CDN & Edge

Where your code runs is as much a decision as what it does. The edge is no longer optional.

18.1 The Edge Landscape

ProviderRuntimeStrength
Cloudflare WorkersV8 isolates (not Node); WinterCG runtime~0ms cold start, 300+ POPs, KV/D1/R2 ecosystem
Vercel Edge FunctionsV8 isolatesTight Next.js integration; ISR; image opt
AWS Lambda@Edge / CloudFront FunctionsNode / lightweight JSAWS-native; less ergonomic
Fastly ComputeWASMPolyglot via WASM; deep CDN integration
Deno DeployDeno runtimeTS-native, fresh-built
Netlify Edge FunctionsDeno runtimeSimple Netlify integration

18.2 What to Run at the Edge

  • Auth checks (validate session cookie at the edge, redirect or return 401 instantly).
  • A/B test bucketing (consistent hashing on user id; pick variant; pass via header to origin).
  • Geo-based redirects / personalization.
  • Bot detection / WAF rules.
  • HTML rewriting (HTMLRewriter API in CF Workers).
  • Cache key normalization.
  • Image optimization.
What NOT to run at edge: heavy computation, anything requiring tight coupling to your origin DB, anything needing Node-specific libraries. Edge isolates have limits (CPU time, memory, no fs).

18.3 CDN Patterns

  • Surrogate keys / Cache Tags for tag-based purge (Fastly, Cloudflare Enterprise).
  • SWR (stale-while-revalidate) headers to serve stale instantly while refreshing background.
  • ISR (Incremental Static Regeneration) for content that changes per minute, not per request.
  • Tiered caching — Cloudflare Argo / Fastly origin shielding.
  • Cache key normalization — strip non-meaningful query params; canonicalize trailing slash.

18.4 Hard Questions

Your origin has p95 latency of 800ms. Most users are in APAC; your origin is in us-east. Walk through the options to get APAC users to < 300ms.
Model: Layered: (1) Move static at the edge — CDN cache HTML, JS, CSS, images. (2) Move SSR to edge — runtime renders at the POP closest to the user; data fetches go back to origin (still slow but only for data). (3) Replicate data closer to APAC — read replicas in ap-southeast; multi-region writes for high-traffic mutations. (4) Edge KV for hot data (sessions, feature flags). (5) Cache HTML at the edge with stale-while-revalidate; even stale-by-30s saves perceived latency for warm content. (6) Optimistic UI for writes; reconcile asynchronously. (7) Measure: synthetic from Singapore + Sydney + Mumbai; RUM by country. Quantify each intervention's impact before generalizing.

18.5 References

19Documentation & Knowledge

Engineering culture is what survives the engineers leaving. Documentation is its substrate.

19.1 The Four Document Types

TypePurposeExamples
ADR / RFCDecisions and rationale"Why we picked Module Federation"
RunbookStep-by-step for incidents"What to do if Lighthouse CI fails on main"
ReferenceSurface description of API/systemStorybook stories, OpenAPI, TSDoc
Tutorial / How-toOnboarding, paved paths"How to add a new feature in our codebase"

Reference: Divio Documentation System — the four-quadrant model.

19.2 What "Good" Looks Like

  • Onboarding doc — new engineer can ship a PR on day 2, not day 12.
  • Architecture overview — a single page diagram + 200 words; not a 40-page wiki nobody reads.
  • Runbook per page for every alert that pages someone.
  • Code lives next to docs — Storybook stories are docs; TSDoc is docs.
  • Docs in the repo, reviewed in PR, not in a separate Confluence.

19.3 Hard Questions

A new engineer says onboarding took 6 weeks. How do you cut that to 2?
Model: Find friction. Sit with the new engineer; document every "I had to ask someone" moment for 2 weeks. Convert each into a doc, a tool, or a process. Common wins: (1) Repo setup script — one command to get to "first PR" state. (2) Architecture explainer with a diagram. (3) Paved-path tutorial: "build feature X in our codebase" with real code. (4) Glossary of internal terms. (5) Codebase tour video (60-90 minutes) per area. (6) "Good first issues" labeled. (7) Buddy pairing for week 1. Measure: time to first PR merged, time to first production deploy.

20Code Review Culture

Code review is the highest-leverage activity in any engineering org. A Lead designs the system as deliberately as any other.

20.1 Principles (Google's eng practices, adapted)

  • Review for the change as it stands, not for what you would have written.
  • Approve when the change improves the codebase, not when it's perfect.
  • Comments are categorized: blocker (must fix), suggestion (consider), nit (style preference), question, praise.
  • Code review SLA: first response within 4 working hours; full review within 24h.
  • Small PRs (< 400 LoC) get reviewed; large PRs get rubber-stamped or postponed.
  • Author responds to every comment (even "noted" or "wontfix because X"). No silent ignore.

20.2 The Tooling Matters

  • CODEOWNERS for automatic reviewer assignment.
  • Required CI green before merge.
  • Stacked PRs for large changes (Graphite, Sapling, git-branchless).
  • AI review (CodeRabbit, Greptile, Diamond) as first-pass — humans focus on architecture.
  • Merge queue (GitHub, Aviator, Mergify) to test mainline state.

20.3 Hard Questions

An engineer keeps shipping 1500-line PRs. How do you change behaviour without losing them?
Model: First, understand why — is it big features with bad scoping, or fear of incomplete-feeling PRs, or unfamiliarity with stacked diffs? Then provide tools and norms together: (1) tooling — set up Graphite or git-branchless; teach the workflow. (2) Norms — codify "PR < 400 LoC" as a guideline with exceptions allowed but flagged. (3) Coaching — pair on splitting one big change into 5 small ones; show the speedup in review time. (4) Reward — celebrate small PRs publicly. (5) Process — if PR > threshold, require a checklist explaining why it can't be split. Don't shame; teach. If after 2 quarters no change, performance conversation. Reference: Google Engineering Practices.

20.4 References

21Browser Internals

A Lead reasons about performance from how the browser actually works — not from React's abstractions.

21.1 The Rendering Pipeline

  1. Parse HTML → DOM tree. Streaming parse; can be paused by script tags (unless async/defer).
  2. Parse CSS → CSSOM. Render-blocking.
  3. JavaScript execution — can read/write DOM and CSSOM; blocks parser unless deferred.
  4. Render tree — DOM × CSSOM, omitting display:none nodes.
  5. Layout (reflow) — compute geometry for every render-tree node.
  6. Paint — fill pixels into layers (a layer per "compositing trigger": transform, opacity, will-change, video, canvas).
  7. Composite — GPU stitches layers together for the final frame.

The fast path bypasses layout and paint — only composite. That's why transform and opacity animations are 60fps-cheap while top/width are expensive.

21.2 The Event Loop

┌─────────────────┐
│   Macrotask     │  ← one per loop turn (setTimeout, setInterval, I/O, UI events)
├─────────────────┤
│   Microtasks    │  ← all drained before next macrotask (Promise.then, queueMicrotask, MutationObserver)
├─────────────────┤
│  requestAnimationFrame callbacks  │  ← before paint
├─────────────────┤
│   Style + Layout + Paint           │
├─────────────────┤
│  requestIdleCallback (if time)     │
└─────────────────┘

Implications: a Promise chain runs before the next setTimeout(0) callback. queueMicrotask lets you piggyback work without yielding to the browser. requestAnimationFrame aligns work with the paint cycle (~16.67ms at 60Hz, 6.94ms at 144Hz).

21.3 Memory Management

  • V8 uses generational garbage collection: young generation (Scavenger, fast), old generation (Mark-Sweep + Mark-Compact, slower).
  • Common leaks: forgotten event listeners on detached DOM, large closures captured by long-lived callbacks, growing arrays in modules, third-party scripts.
  • Diagnose with Chrome DevTools → Memory tab → Heap snapshot + Allocation timeline.
  • WeakRef / FinalizationRegistry for advanced cache scenarios.
  • Profile memory across page navigations in SPAs — leaks compound.

21.4 The Critical Rendering Path

Sequence to first paint: HTML byte → DOM → render-blocking CSS → first layout → first paint. JS in <head> blocks DOM parse. JS without defer/async blocks parsing. CSS in <head> blocks render. Optimizing this path is the foundation of LCP optimization.

21.5 Hard Questions

An animation runs at 30fps on a beefy MacBook. Diagnose.
Model: Open DevTools Performance → record interaction. Look at: (1) Frames pane — green = on-time, yellow = jank. (2) Long Tasks — anything > 50ms is a perf killer. (3) Layout shifts — animating top/height/width instead of transform? (4) Layer count — too many or too few compositing layers? will-change overuse pre-allocates GPU memory. (5) Paint flashing — does the entire viewport repaint on each frame? (6) JS — heavy synchronous work in event handlers or requestAnimationFrame callbacks. Solutions: switch animation to transform: translate3d; offload computation to Web Worker; use CSS animations or Web Animations API instead of JS; check for forced synchronous layout (reading offsetTop after a write).
What's the difference between queueMicrotask and setTimeout(fn, 0)?
Model: queueMicrotask queues in the microtask queue, drained before the next macrotask. setTimeout(fn, 0) is a macrotask — even with 0ms, it waits at least until current microtasks drain + next loop turn (often clamped to 4ms minimum after 5 nested timeouts). Use microtasks for "right after this task" semantics (Promise behaviour); use setTimeout for "yield to the browser" (let it paint, handle input). Modern browsers have scheduler.postTask and scheduler.yield (Chrome 129+) — better than setTimeout for INP.
Explain how the browser decides what becomes its own compositing layer.
Model: Layer creation triggers: 3D transforms (translate3d, translateZ), will-change for transform/opacity, position: fixed/sticky in some cases, video, canvas (sometimes), iframe, opacity < 1 with descendants, certain filter values, overlapping with already-composited siblings. Implications: too many layers = GPU memory pressure (especially on mobile). Too few = expensive repaints on animations. Use DevTools → Layers panel to audit. Cite: Chrome internals — rendering.

21.6 References

22JavaScript Mastery

Past the bootcamp basics. Closures, iterators, generators, proxies, decorators, the proposals pipeline.

22.1 Closures & Lexical Scope

A closure is a function bundled with its lexical environment. The hardest production bug is usually a stale closure — a callback captured an old version of state.

// Stale closure trap
function setupCounter() {
  let count = 0;
  setInterval(() => console.log(count), 1000);  // forever logs 0
  count++;  // unreachable; the closure already captured count=0 at scheduling
}

// In React
function Counter() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setCount(count + 1), 1000);  // stale; count is always 0
    return () => clearInterval(id);
  }, []);  // ← empty deps array = closure baked at mount
  // FIX: setCount(c => c + 1) — functional update reads latest
}

22.2 Iterators & Generators

// Custom iterable
class Range {
  constructor(start, end) { this.start = start; this.end = end; }
  *[Symbol.iterator]() {
    for (let i = this.start; i <= this.end; i++) yield i;
  }
}
for (const n of new Range(1, 5)) console.log(n);

// Async iterators for streams
async function* readLines(file) {
  for await (const chunk of fs.createReadStream(file)) {
    for (const line of chunk.toString().split('\n')) yield line;
  }
}

22.3 Proxies — Use Sparingly

const observed = new Proxy(target, {
  get(t, key, recv) { trackRead(t, key); return Reflect.get(t, key, recv); },
  set(t, key, val, recv) { const r = Reflect.set(t, key, val, recv); trigger(t, key); return r; }
});

Proxies power MobX / Vue reactivity / Valtio. Cost: every access goes through a trap; not free. Use for tooling, not hot paths.

22.4 Patterns Worth Knowing

  • AbortController — cancellation for fetch, listeners, custom async; chainable via signals.
  • Structured Clone — built-in deep clone (structuredClone(obj)).
  • Symbol — unique keys; well-known symbols (Symbol.iterator, Symbol.asyncIterator, Symbol.toPrimitive).
  • WeakMap / WeakSet / WeakRef — for caches that shouldn't prevent GC.
  • Optional chaining + nullish coalescing — but beware a?.b() short-circuits the whole expression.
  • Tagged templates — secure-string DSLs (e.g., SQL via Drizzle).
  • Pipeline operator (Stage 2 proposal) — functional chaining.
  • Decorators (Stage 3) — class & field metadata.
  • Records & Tuples (Stage 2) — value-type immutable structures.
  • Iterator helpers (Stage 4 — shipping) — .map().filter().take() on iterators.
  • Temporal API (Stage 3) — modern date/time replacing Date.

22.5 Hard Questions

Explain how this binding works in JavaScript. Cover arrows, methods, constructors, and explicit binding.
Model: this resolves dynamically at call site (except arrows, which capture lexically). Four rules in precedence order: (1) newthis is the newly constructed object. (2) Explicit binding — .call(thisArg), .apply, .bind. (3) Implicit — object method call obj.fn() sets this to obj. (4) Default — undefined in strict mode, global in sloppy. Arrows have no own this; they capture the enclosing scope's. Class methods are sloppy-equivalent to regular functions; passing as callback loses this unless bound. ES2022 class fields with arrow can give per-instance bound methods. Reference: You Don't Know JS — this & Object Prototypes.
A library function takes a callback and you want to cancel it after 5 seconds without modifying the library. How?
Model: Modern answer: AbortController + signal threading. Wrap the callback to check signal.aborted; set up setTimeout to call controller.abort(). If the library accepts AbortSignal (most modern do, including fetch), pass it directly. If it doesn't: wrap in Promise.race against a timeout promise; the loser is discarded but the work continues until natural completion (so still cleanup the resource). Discuss: AbortSignal.timeout(ms) — built-in shortcut. AbortSignal.any([sig1, sig2]) — compose signals.

22.6 References

23TypeScript Advanced

Beyond strict: true. The type system is a Turing-complete logic programming language — and a Lead uses it that way (judiciously).

23.1 Type-Level Tools

  • Conditional typesT extends U ? X : Y.
  • Mapped types{ [K in keyof T]: U }.
  • Infer keyword — extract types within conditionals: type Awaited<T> = T extends Promise<infer U> ? U : T.
  • Template literal types — type-level string manipulation.
  • Variadic tuple types — spread in tuples.
  • Discriminated unions — narrow by literal tag.
  • Branded types — nominal typing via intersection: type UserId = string & { __brand: 'UserId' }.
  • const generics — preserve literal types via const T extends ....
  • satisfies operator — assert shape without widening.

23.2 Practical Patterns

// Type-safe event emitter
type Events = {
  login: { userId: string };
  logout: { reason: 'manual' | 'timeout' };
};
class Emitter<E extends Record<string, unknown>> {
  on<K extends keyof E>(event: K, handler: (payload: E[K]) => void) { /* ... */ }
  emit<K extends keyof E>(event: K, payload: E[K]) { /* ... */ }
}
const bus = new Emitter<Events>();
bus.emit('login', { userId: 'abc' });  // ✅
bus.emit('login', { reason: 'manual' });  // ❌ TS error
// Builder pattern with type accumulation
class QueryBuilder<T = {}> {
  select<K extends string>(key: K): QueryBuilder<T & Record<K, unknown>> { /* ... */ }
  where(...): this { /* ... */ }
  execute(): T { /* ... */ }
}
const result = new QueryBuilder().select('id').select('name').execute();
// result is { id: unknown; name: unknown }

23.3 The TypeScript Anti-Patterns

  • any — opt-out of typing. Use unknown instead and narrow.
  • as Type casts without runtime checks — bypass the type system at trust boundaries.
  • Overly-clever types that take 5 minutes to understand. Aim for "ergonomic for the consumer, simple-ish in implementation."
  • Re-exporting types from node_modules creating circular type dependencies.
  • Massive single index.d.ts — type errors become slow.

23.4 Performance of the Type System

At Lead scale (50k+ TS files), type-check time matters. Tactics:

  • tsc --diagnostics to see hot paths.
  • Avoid deep recursion in conditional types.
  • Prefer interfaces over type intersections for object shapes (faster to merge).
  • incremental: true for build cache.
  • Project references for monorepo.
  • Migrate to TypeScript native port (Go-based, 10× faster — coming).

23.5 Hard Questions

Design a fully type-safe form library API.
Model: Start from the schema: const schema = z.object({ email: z.string().email(), age: z.number() }). Infer the values type: type Values = z.infer<typeof schema>. The hook returns a typed register that constrains field names to keyof Values and infers value type per field. handleSubmit receives the parsed and validated values type. Errors map is Partial<Record<keyof Values, string>>. Discuss field arrays (nested keys), conditional fields (discriminated union on a tag field), async validation (returns Promise of ValidationResult). Refer to react-hook-form / TanStack Form for inspiration. Mention the Standard Schema spec emerging for cross-validator interop.

23.6 References

24Modern CSS

CSS in 2026 is no longer the language CSS was in 2016. Container queries, layers, scope, view transitions, has(), and color spaces are production-ready.

24.1 Container Queries

.card {
  container-type: inline-size;
  container-name: card;
}
@container card (min-width: 400px) {
  .title { font-size: 1.5rem; }
}

Queries the component's own width, not the viewport. Game-changer for design systems.

24.2 Cascade Layers

@layer reset, base, components, utilities;

@layer reset { /* normalize.css */ }
@layer base { body { font-family: sans-serif; } }
@layer components { .btn { padding: 0.5rem 1rem; } }
@layer utilities { .text-sm { font-size: 0.875rem; } }

Layered cascade beats specificity wars. Later layers always win over earlier (unlayered styles beat layered).

24.3 CSS :has() — The Parent Selector

/* Card with an image gets extra padding */
.card:has(img) { padding-bottom: 2rem; }

/* Form with invalid input shows error styling on the wrapper */
.form-row:has(input:invalid) { border-color: red; }

/* Hide siblings of focused element */
.menu li:not(:has(a:focus)) { opacity: 0.5; }

24.4 View Transitions API

// SPA route change with cross-fade
document.startViewTransition(() => {
  updateDOMForNewRoute();
});

// CSS to customize
::view-transition-old(root) { animation: fade-out 0.3s; }
::view-transition-new(root) { animation: fade-in 0.3s; }

Cross-document view transitions (Chrome 126+) enable transitions across full page loads — previously only possible in SPAs.

24.5 Modern Color & Typography

  • color-mix(in oklch, ...) — programmatic color mixing in perceptual color spaces.
  • oklch() / oklab() — perceptually uniform color; better for design tokens than HSL.
  • color() with display-p3 — wide-gamut for compatible screens.
  • relative color syntax — derive variants: oklch(from var(--primary) calc(l - 0.1) c h).
  • text-wrap: balance — heading line-balancing.
  • text-wrap: pretty — better line-breaking in paragraphs.
  • variable fonts — single file, axis-controlled (weight, width, slant); often smaller than 4 static files.

24.6 Scroll-Driven Animations

@keyframes reveal { from { opacity: 0; } to { opacity: 1; } }
.card {
  animation: reveal linear;
  animation-timeline: view();
  animation-range: entry 0% cover 30%;
}

Native CSS scroll-linked animation. No JS, no IntersectionObserver. Chrome 115+, Firefox preview, Safari coming.

24.7 Logical Properties (RTL-Ready)

PhysicalLogical
margin-left, margin-rightmargin-inline-start, margin-inline-end
padding-top, padding-bottompadding-block-start, padding-block-end
top, leftinset-block-start, inset-inline-start
width, heightinline-size, block-size
text-align: lefttext-align: start

24.8 Hard Questions

Why is OKLCH replacing HSL for design tokens?
Model: HSL is not perceptually uniform — equal lightness values produce visually different brightnesses (yellow at L=50 looks much lighter than blue at L=50). OKLCH is based on perceptual color science (Oklab color space, Björn Ottosson 2020). Equal L values look equally bright. Critical for accessible contrast tokens, for hue-rotation that stays at consistent perceived brightness, for color palettes algorithmically generated. Browser support is universal now. Cite: evil martians OKLCH article · oklch.com.

24.9 References

25React Internals

A Lead understands what React does to memory and to the main thread — not just what hooks do.

25.1 The Reconciliation Model

React maintains two trees: current (committed) and work-in-progress (rendering). On a state change, React builds the WIP tree by re-rendering components, diffs against current, and commits changes to the DOM in a single batched flush. Since React 18, this is interruptible — concurrent rendering means the WIP tree can pause for higher-priority work (user input).

25.2 Fiber Architecture

Each component instance gets a "fiber" — a JS object holding component type, props, state, effects, and pointers to parent/child/sibling fibers. The reconciler walks fibers, not directly the DOM. Walking is cooperative — React can yield between fibers if the deadline expires.

25.3 Hooks — How They Actually Work

Each fiber has a linked list of hook instances. On render, React positionally matches calls — first call is the first hook in the list, second is the second, etc. That's why hooks must always be called in the same order (the "no conditional hooks" rule). The hook list is recreated on every render of the same fiber.

25.4 React 19 Highlights (deep)

  • use() — read a promise or context conditionally. Suspends the calling component until the promise resolves. Enables RSC's "await data inline."
  • React Compiler (Forget) — analyzes components at build, inserts memoization automatically. Removes 90%+ of manual useMemo/useCallback.
  • Actions & useActionState — async transitions; pending state, optimistic updates, form integration.
  • useOptimistic — built-in optimistic UI primitive.
  • Refs as props — no more forwardRef in most components.
  • Document Metadata<title>, <meta> inside components are hoisted to <head>.
  • Resources<link rel="stylesheet" precedence> deduped and reordered automatically.
  • preinit / preload / prefetchDNS — programmatic resource hints.
  • Improved hydration errors — diffs reported clearly.

25.5 Server Components — The Mental Model

RSC are components that render on the server and ship a serialized tree (not HTML) to the client. The client merges them with client components ("islands"). RSC can:

  • Use async/await for data fetching inline.
  • Access the server filesystem, environment, databases directly.
  • Ship zero JS to the client (the RSC payload describes the tree, not the source).

RSC cannot:

  • Use state hooks (useState, useReducer) — they have no client lifecycle.
  • Use effect hooks.
  • Attach event handlers (unless via client component child).
  • Use browser APIs.

'use client' at the top of a file marks everything in that module as client. A server component can import and render a client component, but not vice versa.

25.6 Hard Questions

Explain selective hydration in React 18.
Model: Pre-18, hydration was all-or-nothing — the entire tree had to hydrate before any interaction worked. With React 18, Suspense boundaries break this: each boundary hydrates independently as its JS arrives. If a user clicks an unhydrated region, React prioritizes hydrating that subtree first (selective hydration). Combined with streaming SSR, this means: server flushes HTML in chunks as data resolves, client hydrates chunks in priority order based on user attention. End-user impact: TTI on a complex page can be cut significantly because the visible-above-fold hydrates first, while below-fold streams in. Reference: React 18 Working Group — Suspense in React 18.
When should you NOT use the React Compiler?
Model: The compiler relies on Rules of React being followed (no mutation of props/state, no calls during render, hooks at top level). Code that breaks these rules (often in older codebases or third-party libs) may produce wrong output when compiled. Use the eslint-plugin-react-compiler to audit; opt out specific files via "use no memo" directive. Also: for libraries that ship to consumers, compiled output is less inspectable — consider shipping un-compiled. For very small components where overhead of memoization checks dominates, the compiler may add work for no win — but this is rare.

25.7 References

26Networking

HTTP/3, WebTransport, WebSockets, Server-Sent Events, BroadcastChannel — picking the right transport is a Lead decision.

26.1 HTTP Evolution

VersionKey ChangeFE impact
HTTP/1.1Persistent connections, pipelining (rarely works)Browsers cap at 6 connections per origin → bundle assets
HTTP/2Multiplexing on one connection, header compression, server push (deprecated)Many small requests OK; bundling less critical
HTTP/3 (over QUIC)UDP-based, eliminates head-of-line blocking at transport, faster handshakeBetter on lossy networks; deployed at CF, Akamai, Fastly
103 Early HintsServer can send preload hints before final responseImproves LCP by ~100ms on slow origins

26.2 Real-time Transports

TechDirectionBest for
WebSocketFull duplexChat, collaborative editing, real-time games
Server-Sent Events (SSE)Server → ClientNotifications, live feeds, LLM token streaming
WebTransportMultiple streams + datagrams over HTTP/3Future of low-latency apps (browser support emerging)
WebRTCP2P + signaling serverVideo, voice, low-latency data channels
Long pollingClient requests, server holdsFallback when WS blocked by corporate proxies
BroadcastChannelSame-origin tabsCross-tab UI sync without a server

26.3 Picking Between WS and SSE

SSE wins for server-push-only data: simpler protocol (just HTTP), auto-reconnect with last-event-id resume, works with HTTP/2 multiplexing, no CORS gymnastics, easy to scale (CDN-friendly). LLM streaming is the classic 2024+ use case. WebSocket wins when client also pushes frequently (chat input, mouse cursors in collaborative editor).

26.4 Hard Questions

Your real-time feature is dropping events under load. How do you reason about it?
Model: (1) Which leg drops? Producer → server (network), server processing (backpressure), server → consumer (slow consumer disconnected). Add metrics per leg. (2) What's the at-least-once guarantee? If clients reconnect, do they replay? Use sequence numbers + server-side buffer with TTL; clients ack offsets. (3) Order vs liveness — Kafka-style: prefer ordered + slightly stale; chat-style: prefer live + dropped messages. (4) Backpressure — limit per-connection queue size; disconnect slow consumers; expose backpressure to server-side producers. (5) Scale horizontally — sticky sessions (consistent hash) OR stateless servers + Redis pub/sub for fan-out. Discuss CRDT-based approaches for collaborative apps where final-state convergence matters more than ordering.

26.5 References

27Web Standards & Platform APIs

The platform shipped a lot in 2023-2025. Lead engineers should know what's possible without npm install.

27.1 APIs Worth Knowing

  • IntersectionObserver — lazy-load, infinite scroll, ad viewability without scroll listeners.
  • ResizeObserver — element-size-aware layouts.
  • MutationObserver — react to DOM changes (third-party iframes, legacy code).
  • PerformanceObserver — capture LCP, FID/INP, long tasks, layout shifts.
  • Long Animation Frames (LoAF) — replaces Long Tasks; catches the things hurting INP.
  • Navigation API — replaces History API + popstate; promise-based, intercept-able.
  • View Transitions — animated state changes between DOM trees.
  • Popover API — native popovers without JS (Chrome 114+, Safari 17+).
  • Dialog element — native modal with backdrop, ESC handling, focus trap (partial).
  • BroadcastChannel — cross-tab messaging.
  • File System Access API — read/write user files (Chrome only).
  • Web Share API — native share dialog on mobile.
  • WebAuthn / Passkeys — phishing-proof auth.
  • FedCM — federated identity replacing third-party cookies.
  • Web Workers / Service Workers / Shared Workers — different scopes of off-main-thread.
  • WebAssembly + WASI — near-native compute in browser.
  • Web Bluetooth / USB / Serial / HID — hardware access (Chrome).
  • Web Speech API — text-to-speech and speech-to-text.
  • Web Animations API (WAAPI) — programmatic CSS animations.
  • Web Locks API — coordinate across tabs (e.g., one tab leader for IndexedDB writes).
  • Storage API — quota estimates, persistent storage requests.
  • OffscreenCanvas — canvas rendering on a Web Worker.

27.2 Hard Questions

You're building a "table of 100k rows with sort/filter." Walk through the architecture without a framework.
Model: (1) Virtualization — render only visible rows; use IntersectionObserver to mount/unmount; for variable row heights, use TanStack Virtual or react-window with measured heights cached. (2) Sort/filter off-main-thread — Web Worker with Comlink; transfer data via SharedArrayBuffer if very large. (3) Indexes — pre-built sort indexes per column; binary search for filters. (4) Incremental rendering — show first 50 rows ASAP, then chunks via requestIdleCallback. (5) Stable identity — key by row id, not index; React reconciliation depends on it. (6) Scroll perf — passive event listeners, debounced layout, content-visibility: auto on rows for skip-rendering. (7) Server-side option — if data is huge, push sort/filter to the server with cursor-based pagination. (8) Accessibility — virtualization breaks Cmd+F find-in-page; mitigate with semantic table + ARIA + skip-link to load all. Cite AG Grid, MUI X Data Grid as references.

27.3 References

28PWA & Offline-First

Service workers are how the web shipped its strongest feature in the last decade. Most teams still don't use them well.

28.1 The Service Worker Lifecycle

  1. Register — JS calls navigator.serviceWorker.register('/sw.js').
  2. Install — once per version; cache assets via caches.open(...).addAll(...).
  3. Activate — clean up old caches; self.clients.claim() for instant control.
  4. Fetch — intercept every navigation and asset; programmable caching.
  5. Update — browser checks sw.js for byte changes; new SW installs in background, waits for tabs to close.

28.2 Cache Strategies

StrategyBehaviourBest for
Cache-firstCache → fallback to networkHashed static assets (immutable)
Network-firstNetwork → fallback to cacheHTML pages — fresh wins, offline-safe
Stale-while-revalidateCache immediately + background refreshFrequently-updated content where stale is OK briefly
Network-onlyAlways networkMutations, auth, real-time
Cache-onlyNever networkApp shell after install

Workbox abstracts these as one-liners. Reference: Workbox docs.

28.3 Hard Questions

Your service worker is serving stale assets after a deploy. Users see old UI for hours. Fix.
Model: Multi-layer issue. (1) SW update detection — service workers update on navigation; if user keeps the tab open, the new SW installs but stays in "waiting" until all tabs close. Solution: self.skipWaiting() in install + self.clients.claim() in activate, but warn that this can break in-flight requests; safer is to show an "update available" toast and call skipWaiting on user click. (2) HTML caching too aggressive — never cache HTML at the SW with long TTL; use network-first. (3) Asset hash mismatch — ensure assets are content-hashed; old SW caches old hashed assets, new SW caches new ones; no overlap. (4) Cache versioning — bump cache name on every deploy; activate handler purges old caches. (5) HTTP cache on top of SW — ensure SW responses have correct Cache-Control. (6) Kill switch — ship an "unregister-all" SW as last resort. Cite Workbox patterns.

28.4 References

29Frontend System Design — Framework

FE system design is the most distinctive part of a senior-to-staff interview. There's a structured way to approach every problem.

29.1 The RADIO Framework

Popularized by GreatFrontEnd; the most cited framework for FE system design.

  1. Requirements clarification
  2. Architecture / high-level design
  3. Data model
  4. Interface (API + component API)
  5. Optimizations (perf, a11y, security, offline, error handling, scaling)

Reference: GreatFrontEnd — RADIO framework

29.2 Requirements — The Right Questions

  • Functional: what does the user do? Main flows? Edge cases?
  • Audience: who, where (geo), what devices, what network?
  • Scale: DAU/MAU, concurrent users, peak QPS?
  • Non-functional: p95 latency, accessibility, SEO, offline support, localization?
  • Constraints: existing backend, tech stack, team skills, deadline?
  • Out of scope: what won't you discuss (auth, signup, billing)?

29.3 Architecture Diagrams

Draw three boxes minimum: client, server (or BFF/API gateway), backend (services + data store). Add CDN/edge layer. Identify the network hops. For each hop, label payload shape and frequency.

29.4 Data Model

List entities, their relationships, the shape returned to the client. Mention normalization (cache shape) vs denormalization (transport). Discuss pagination strategy (offset/cursor/keyset). Discuss freshness — what's cached for how long.

29.5 Interface

API endpoints (REST or GraphQL queries). Component API — what the consumer sees: props, callbacks, slots. Loading/error/empty states explicitly defined.

29.6 Optimizations Checklist

AreaTactics to mention
PerformanceCode splitting, lazy load, virtualization, image opt, SSR/RSC, prefetch, Web Workers
NetworkBatch, dedup, cache, optimistic update, retry with backoff, offline queue
AccessibilitySemantic HTML, ARIA, keyboard, screen reader, focus mgmt, color contrast
SecurityXSS, CSRF, CSP, token handling, rate-limit-aware client
i18nRTL, plural rules, date/number formatting
ReliabilityError boundaries, retry, graceful degradation, offline detection
ObservabilityErrors, RUM, custom telemetry, A/B test instrumentation
TestingUnit, integration, E2E, visual regression, a11y

29.7 References

30Design: News Feed

The canonical FE system-design question. Used at Meta, Twitter, LinkedIn, TikTok.

30.1 Requirements (clarify first)

  • Vertical infinite scroll, posts with text/image/video, like/comment/share.
  • Personalized ranking (server-side); client just renders.
  • 10M DAU; reads >> writes.
  • Web + mobile web; deep links; share-to-anywhere.
  • Real-time new-post indicator ("3 new posts" pill at top).

30.2 Architecture

  • SSR or RSC for initial page (SEO + fast LCP for the first 5–10 posts).
  • Client-side hydration; subsequent pages fetched via cursor pagination.
  • Edge cache for unauth feed (logged-out homepage); per-user cache for auth feed (short TTL).
  • WebSocket or SSE for new-post notifications (push count, not the posts themselves).
  • Image CDN with responsive variants (srcset, AVIF), video as HLS/DASH.

30.3 Data & Pagination

// Cursor-based pagination (preferred over offset)
GET /feed?cursor=eyJ0cyI6MTcwOH0&limit=20

{
  posts: [...],
  nextCursor: "eyJ0cyI6MTcwOX0",
  hasMore: true
}

Cursor pagination handles "new posts arriving while user scrolls" correctly (offset would skip or duplicate). Stable across sessions when cursors are opaque ts+id tuples.

30.4 Virtualization & Memory

  • Use TanStack Virtual or react-window with measured heights. Naive infinite scroll renders 100s of DOM nodes — memory grows.
  • Recycle DOM via virtualization OR unmount far-offscreen posts and remount on re-entry (LRU).
  • content-visibility: auto on each post — skips render for off-screen items.
  • Image lazy-load with IntersectionObserver; loading="lazy" attribute as fallback.

30.5 Optimistic Interactions

  • Like: increment count immediately, POST in background; rollback on error.
  • Comment: append optimistic comment with grey state; replace with server response or retry.
  • De-duplicate concurrent mutations.

30.6 Performance Targets

  • LCP < 2.0s p75 (above-fold first post + image).
  • INP < 100ms (like button must feel instant).
  • Scroll FPS > 50 on mid-tier Android.
  • Initial JS < 200KB compressed.

30.7 Edge Cases

  • Post deleted while user viewing — fade-out with explanation.
  • Network drops mid-scroll — show "tap to retry" within the empty space.
  • Auto-play video on Wi-Fi only; respect prefers-reduced-motion.
  • Same post viewed in multiple tabs — like state sync via BroadcastChannel.

30.8 References

31Design: Collaborative Editor (Google Docs / Figma / Linear)

The hardest problem in FE system design — concurrency, consistency, and offline.

31.1 The Core Question: OT vs CRDT

Operational Transformation (OT)CRDT
ApproachOperations rebased against concurrent ops on a central serverData structures designed to converge regardless of order
Server roleRequired — applies transformsOptional — can be P2P
ComplexityHard transform functions; lots of edge casesComplex data structures but composable
ExamplesGoogle Docs, Etherpad, ShareJSYjs, Automerge, Liveblocks, Linear's Sync Engine
Trend (2025+)Mature, used in large productsRapidly mainstream — favored for new apps

31.2 Architecture (CRDT-based, like Yjs)

  • Client maintains a local Y.Doc instance — single source of truth for the user.
  • Edits are local mutations; converted to binary "updates" by Yjs.
  • Updates sync via WebSocket to a server (or directly to peers via WebRTC).
  • Server is "dumb" — relays updates and persists snapshot+log.
  • Conflict resolution is automatic by CRDT properties — concurrent edits merge deterministically.
  • Presence (cursors, selections) on a separate ephemeral channel.

31.3 Hard Sub-problems

  • Garbage collection — CRDT tombstones accumulate; periodic compaction needed.
  • Initial load — load snapshot then replay since-snapshot updates. Latency budget matters.
  • Permissions — server can't trust client; document-level ACL gate on the WS.
  • Undo/redo — local undo stack vs collaborative undo (only undo your own changes).
  • Large documents — chunking strategies; lazy-load offscreen pages.
  • Offline edits — local IndexedDB persistence; reconcile on reconnect.
  • Cursor presence — debounce broadcast; subscribe only to visible users.

31.4 Linear's Sync Engine — Worth Studying

Linear ships an in-process client database synchronized with the server; all UI reads from the local store; all writes go through optimistic mutation + reconciliation. Result: every interaction is instant. Reference: Linear engineering — scaling sync.

31.5 Hard Questions

How do you handle 100 users editing the same document?
Model: Backend can shard documents to a single server per doc (so all writers hit one server); presence updates go through that server. WS connections are sticky-routed by document id. Updates broadcast to all connected clients. CRDT guarantees convergence even if reordered. Tune: presence updates throttled to 10–20Hz; edits flushed in 50ms batches per client. For 100 users, total < 1 MB/s ingress per doc — modest. Monitor server's per-doc memory; offload to disk for cold documents. For documents with truly massive concurrent edits (Figma at scale): partition by document region / layer; multi-server orchestrator.

31.6 References

32Design: Autocomplete / Typeahead

Looks simple. Has every interesting FE problem in 30 lines of code.

32.1 Requirements to Clarify

  • Latency target — feels instant means < 100ms perceived.
  • Trigger threshold (2 chars? 1 char?).
  • Recent / popular suggestions even without typing.
  • Keyboard navigation (Up/Down/Enter/Esc).
  • Accessibility — ARIA combobox pattern.
  • Result count, ranking, highlighting.

32.2 Architecture

  • Client debounces input (~150-300ms).
  • Request only if query changed; AbortController cancels in-flight on new input.
  • Cache key by query string; LRU eviction.
  • Prefetch popular suggestions at idle.
  • Server: dedicated search service (Elasticsearch / Algolia / Typesense / Meilisearch) — frontend hits this directly with auth token.
  • Edge caching for popular queries; bypass for personalized.

32.3 The Race Condition Trap

// ❌ Race: user types "ne", "new", "news" — responses may arrive out of order
async function search(q) {
  const res = await fetch(`/search?q=${q}`);
  setResults(await res.json());
}

// ✅ AbortController cancels prior
let ctl;
async function search(q) {
  ctl?.abort();
  ctl = new AbortController();
  try {
    const res = await fetch(`/search?q=${q}`, { signal: ctl.signal });
    setResults(await res.json());
  } catch (e) { if (e.name !== 'AbortError') throw e; }
}

32.4 Hard Questions

Walk me through ARIA for an autocomplete with combobox pattern.
Model: Input has role="combobox", aria-expanded reflecting popup open, aria-controls="listbox-id" pointing to the listbox, aria-autocomplete="list" or "both", aria-activedescendant pointing to the highlighted option id. Listbox has role="listbox"; each result role="option" with unique id and aria-selected. Live region announcing result count ("5 results, use arrow keys to navigate"). Keyboard: Down opens + highlights first; Up/Down navigate; Enter selects; Esc closes restoring focus to input; Tab closes and tabs away. Reference: APG Combobox.
Users in India report autocomplete is laggy. Diagnose.
Model: RTT to search backend likely dominates. (1) Move search index closer — Algolia/Typesense have multi-region replicas. (2) Edge cache popular queries for that region. (3) Prefetch on focus (warm DNS + TLS). (4) Reduce payload — return only fields needed for display. (5) Local index for common cases — fuse.js or Lyra for client-side fuzzy match if dataset fits in memory; combine with remote for fresh long-tail. (6) Optimistic local highlight before server confirms. (7) Connection reuse — HTTP/2 or /3 to the search endpoint. (8) Show last-results stale while fresh loads. Measure: per-region p75 of "keypress to first result paint."

32.5 References

33Design: Video Player

Video is where FE meets media engineering. Adaptive bitrate, DRM, captions, low-latency.

33.1 Core Concepts

  • HLS (HTTP Live Streaming) — Apple's protocol, m3u8 manifest + .ts/.mp4 segments. Default for web/iOS.
  • DASH — Google/Netflix; xml manifest + MP4 segments. Common for Android/desktop.
  • WebRTC — for <500ms latency (live shopping, interactive).
  • LL-HLS — low-latency HLS (sub-3s).
  • MSE (Media Source Extensions) — JS API for ABR streaming via append-buffer model.
  • EME (Encrypted Media Extensions) — for DRM (Widevine, FairPlay, PlayReady).
  • Players — Shaka (Google, supports DASH+HLS), Video.js, HLS.js, dash.js, Mux Player.

33.2 The ABR (Adaptive Bitrate) Loop

  1. Player downloads manifest with multiple quality levels.
  2. Measures bandwidth via segment download time.
  3. Chooses next segment quality based on bandwidth + buffer level + heuristics.
  4. Aims to keep buffer 10-30s, never empty.
  5. Throttles up on stability, throttles down on stall risk.

33.3 Hard Sub-problems

  • Autoplay restrictions — muted required on most browsers; user gesture required for sound.
  • Captions — WebVTT format; accessibility critical (FCC compliance for streaming services).
  • Subtitle styling — render in DOM (more control) or via native track (better a11y).
  • Picture-in-picture — PiP API.
  • Background playback — Media Session API for lock-screen controls.
  • Watch history / resume — debounced position save.
  • DRM provisioning — license server, key rotation.
  • Analytics — startup time, rebuffer ratio, average bitrate, quality switches, errors. QoE (Quality of Experience).

33.4 References

34Design: Chat / Realtime Messaging

Slack, WhatsApp Web, Discord — same problem, similar architecture.

34.1 Architecture Sketch

  • WebSocket connection per user; sticky-routed to a "channel server."
  • Server fan-out to all members of the channel (room).
  • Message persisted to DB before fan-out (durability).
  • Sequence number per channel for ordering; client uses this to detect missed messages on reconnect.
  • Read receipts via separate lightweight events (debounced).
  • Typing indicators via short-lived events (TTL 5s).
  • Presence — heartbeat over WS; aggregated to "online/offline/idle" indicator.

34.2 Client-Side Data Model

  • IndexedDB for offline persistence; messages keyed by (channel_id, sequence).
  • Optimistic local-id for sent messages; reconcile to server-id on ack.
  • Read-only normalized cache (Apollo-style) for users, channels, members.
  • Virtualized message list (huge channels render only visible window).

34.3 Hard Sub-problems

  • Reconnection without missing messages — on reconnect, client sends last_seq; server replays from durable log.
  • Order across servers — sticky routing keeps per-channel order; cross-channel order is per-channel only.
  • Mute / DND / per-channel notification settings — server-evaluated.
  • End-to-end encryption — Signal Protocol; client-side encryption; server never sees plaintext.
  • Edit and delete — append "edited" event; client rewrites local state.
  • Rich content — markdown, mentions, attachments; lazy-load attachments.
  • Notifications — push via FCM/APNs when web app closed.

34.4 References

35Design: A Company-Wide Design System

Not "a component library." A product with users, an API, a migration story.

35.1 Requirements

  • 50 product teams; 5 product brands sharing a design language.
  • Web + React Native (or Flutter); shared design tokens.
  • Accessible by default (WCAG 2.2 AA minimum).
  • Independent versioning; consumers upgrade at their pace.

35.2 Architecture

  • Token layer (JSON, generated to CSS vars, iOS XCAssets, Android XML).
  • Primitives layer (Box, Stack, Text, Button, Input — built on Radix / React Aria).
  • Patterns layer (Card, Modal, Toast, Form — composed primitives).
  • Templates layer (Dashboard shell, Marketing landing, Settings page).
  • Per-brand theme overrides via tokens, not forks.

35.3 Operating Model

  • Central DS team owns the platform; product teams contribute via federated model (RFC + PR).
  • Office hours, Slack channel, monthly demo.
  • Metrics: adoption rate (% PRs using DS components), versions in use, time-to-upgrade.
  • Quarterly migration goals; codemods for every breaking change.

35.4 Hard Questions

A product team forks a button. How do you prevent this from becoming the norm?
Model: First, accept that occasional forks are signals — your DS isn't meeting a real need. Diagnose every fork: missing variant (add it), genuine escape (provide composition primitive like asChild / slot), fundamentally different component (introduce a sibling primitive). Make contribution easy — clear PR template, 1-week review SLA. Measure forks; share the metric in the design system steering committee. Provide a "design system upgrade quarter" so teams can pay back the debt. Make forks visible — automated PR comment when a custom component is detected duplicating a DS one. Carrot, not stick: highlight teams who contribute back, ship DS releases with their names.

35.5 References

36AI in the Frontend

In 2026, a Lead FE is judged on two AI dimensions: how they ship AI features, and how they use AI in their own workflow.

36.1 Building User-Facing AI Features

  • Vercel AI SDK — high-level wrapper for streaming, tool calling, RAG, multi-model.
  • LangChain.js / LangGraph.js — orchestration of multi-step agent flows.
  • LlamaIndex.ts — RAG-focused.
  • Streaming UI patterns — Server Components + RSC streams, Edge functions piping SSE.
  • Tool calling — model returns structured calls; FE renders custom UI per tool result.
  • Inline citations + grounding — display sources next to claims.
  • Cost / token budgeting — UI for premium users, fallback for free.
  • Failure modes — what UX shows when the model is slow, wrong, or unavailable.

36.2 LLM-Native UX Patterns

  • Streaming tokens — render progressively; never spinner-then-dump.
  • Stop generation — user-cancellable; AbortController.
  • Regenerate / try again — easy to retry.
  • Edit and resubmit — revise prior message rather than starting over.
  • Markdown / code rendering — react-markdown with safe whitelist; Prism/Shiki for syntax highlighting.
  • Generative UI — RSC + tool calls producing typed React components rather than text.
  • Tool result UI — chart for chart-tool, table for query-tool, map for places-tool.
  • Source citations — clickable, with provenance.
  • Conversation persistence — server-side history; resume across devices.
  • Multi-turn context windows — manage context length, summarize older turns.

36.3 AI in Developer Workflow

ToolCategoryUsed for
GitHub CopilotInline completionBoilerplate, scaffolding
CursorIDEMulti-file edits, agentic refactors
Claude Code / Claude DesktopAgent / chatArchitecture, code review, doc generation
WindsurfIDECursor competitor
v0.devUI scaffoldingPrompt → React + Tailwind components
Bolt.new / LovableApp scaffoldingPrototypes, MVPs
Aider / Cline / ContinueAgentPair programming from terminal/editor
CodeRabbit / Greptile / DiamondAI PR reviewAutomated first-pass review
MCP serversIntegration protocolConnect AI to data sources, APIs

36.4 Hard Questions

Design a streaming chatbot UI with tool-calling and citations. Walk me through the architecture.
Model: Architecture: client opens an SSE connection to a Next.js Edge function (or any framework with streaming). Server starts LLM call, streams tokens back. Tool calls emerge in the stream as structured events (e.g., data: {"type":"tool_call","name":"search","args":{...}}); server executes tool, returns results, model resumes with augmented context. Client maintains a state machine of message parts: text-token, tool-call, tool-result, citation. Each part rendered with its own React component. Token-level state update is too chatty — batch via requestAnimationFrame. Auto-scroll if user is at bottom; pause auto-scroll if user scrolls up. Stop button calls AbortController on the SSE stream. Reference: Vercel AI SDK.
How do you prevent AI tooling from degrading code quality at the team level?
Model: Treat AI like a junior pairing partner — productive, not autonomous. Concrete controls: (1) Project rules files (.cursorrules, CLAUDE.md) encoding conventions. (2) Strong CI — types, lint, tests catch the things AI gets wrong. (3) Code review discipline — reviewers don't rubber-stamp because "the AI wrote it." (4) Banned patterns — no AI for security-sensitive code, no AI for crypto, no AI-generated regex without review. (5) Team culture — celebrate the engineer who pushed back on bad AI suggestion. (6) Measure: track bug rate by author; doesn't change much when AI use scales. (7) Training: regular team sessions on prompt patterns that work, anti-patterns that don't. Discuss: AI-velocity-without-AI-quality is a trap.

36.5 References

37Edge & Server Components Deep-Dive

RSC + edge is the most significant architectural shift since the SPA. A Lead can argue for and against it.

37.1 The Mental Reset

  • Components run on the server, ship serialized tree.
  • Client receives "instructions" not HTML — a React-internal binary format.
  • Server components can await anything.
  • Client components are explicit ('use client') — and become the islands of interactivity.
  • Server Actions are functions on the server callable from client; they replace many API routes.

37.2 Trade-offs

ProCon
Smaller JS bundle (server-only code never ships)Two execution models in one codebase; mental overhead
Data fetching inline, no client-side waterfallClient state and server data tightly coupled in dev experience
Direct DB access in componentsEasy to over-fetch or fan out N+1 if not careful
Suspense + streaming gives great LCPTooling immaturity — testing RSC is harder
Forces a layered architectureEcosystem fragmented — libraries declare client/server compat differently

37.3 Anti-patterns

  • Passing huge server-fetched objects to client components — they get serialized in the RSC payload.
  • Using 'use client' on a leaf rather than the boundary — it cascades.
  • Calling Server Actions from useEffect — defeats the point; use them on form submit.
  • Mixing server-only env vars with client components — leaks at build.

37.4 References

38Cross-Platform Considerations

38.1 The Choices

StackApproachBest for
React Native + ExpoNative UI via bridgeTrue-native feel; large user base
FlutterCustom renderer (Skia)Pixel-perfect cross-platform; non-React orgs
Capacitor / IonicWebview + native pluginsCode reuse across web + mobile; less native feel
TauriWeb frontend + Rust backendLightweight desktop apps
ElectronWeb frontend + Node backendMature; heavy memory; VS Code, Slack
PWAWeb installedWhen app-store is not required
Lynx (ByteDance)React-syntax cross-platform UIEmerging

38.2 Code Sharing Strategies

  • Share types, models, business logic (TypeScript packages in monorepo).
  • Share UI primitives where possible (Tamagui, Solito for RN+Web shared components).
  • Platform-specific UI for high-touch surfaces (navigation, gestures).
  • Share networking, validation, state libraries.

38.3 Hard Questions

A company wants one codebase for iOS, Android, and web. Defend or push back.
Model: Push back gently. "One codebase" is a goal, not a strategy. What's the user need? If feature parity is identical and brand experience is identical, RN + RN Web (via Solito or Tamagui) is feasible. Realistically: 80% UI shared, 20% platform-specific. Backend, models, tests, types are easily shared. UI nuances (iOS swipe gestures, Android material patterns) need platform code. Measure: if you save 50% engineering but lose 20% UX quality, that's often a bad trade for consumer products. For internal tools or B2B: web-only PWA + Capacitor wrapper is often enough. Cite: Airbnb famously moved away from RN, then Meta and Discord double-down; each context differs.

38.4 References

39Tech Debt & Migration

A Lead is judged on their ability to make hard migrations land without melting the team or the product.

39.1 The Migration Playbook

  1. Define done — what state is target? Be specific.
  2. Strangler fig — incremental, not big-bang.
  3. Codemod first — automate every mechanical change.
  4. Branch by abstraction — toggle between old and new behind an interface.
  5. Owner per migration unit — accountability prevents drift.
  6. Dashboards — % migrated, ETA, blockers visible.
  7. Deprecation policy — old API works until date X; warn in logs.
  8. Removal phase — only after 100% migration metrics + 1 quarter buffer.

39.2 Common FE Migrations

  • Webpack → Vite/Rspack/Turbopack
  • Jest → Vitest
  • ESLint legacy config → flat config (or → Biome)
  • styled-components → vanilla-extract / Tailwind
  • Class components → functional
  • React Router v5 → v6 → v7
  • Pages Router → App Router (Next.js)
  • Moment.js → date-fns / Day.js / Temporal
  • Redux → Zustand / RTK Query / TanStack Query
  • npm/yarn → pnpm

39.3 Hard Questions

Migrate 200 product engineers from Webpack to Vite. Plan.
Model: (1) Pilot — pick one app; ship it; measure (build time, dev start, bundle size). (2) Document gotchas — Jest tests (often need Vitest), require/import compat, plugin ecosystem differences, env var conventions (process.env vs import.meta.env). (3) Codemods — for common patterns. (4) Migration template repo — engineers copy config. (5) Office hours — DS/Platform team available. (6) Quarterly target — % apps migrated; dashboard. (7) Removal date — old Webpack config deleted from CI on date X. (8) Reward early adopters — public recognition. Reference: how Shopify migrated to esbuild — gradual, measured, communicated.

39.4 References

40Hiring, Mentoring & Team Building

40.1 What Leads Are Judged On

  • Velocity of the team (DORA metrics).
  • Quality of output (defect rate, customer-impacting incidents).
  • People you brought up (promotions, growth conversations).
  • Hiring bar maintained (or raised).
  • Cross-team influence (RFCs you drove, standards you proposed).
  • Sustainability (no heroics, no burnout, on-call humane).

40.2 Hiring Loop You Should Design

  • Recruiter screen (45 min) — alignment, scope.
  • Hiring manager (45 min) — motivation, growth, fit.
  • Coding round (60-90 min) — practical problem, no leetcode trick.
  • FE system design (60 min) — RADIO problem.
  • Behavioral / leadership (60 min) — STAR stories.
  • Bar raiser / cross-team (45 min) — Amazon-style independent assessment.
  • Optional: take-home (timed, capped) for senior candidates uncomfortable with whiteboard.

40.3 Mentoring Engineers

  • Weekly 1:1s — agenda owned by the report, not you.
  • Growth plan — concrete, time-boxed, measurable.
  • Stretch projects — assigned with safety net (pairing, rollback plan).
  • Public feedback loop — code review is a teaching opportunity, not just a quality gate.
  • Sponsorship over mentorship — talk about them when they're not in the room.

40.4 Hard Questions

Two of your senior engineers disagree fundamentally on architecture. How do you resolve?
Model: First, separate technical from interpersonal. Get the technical down on paper — both write a 1-page RFC of their position. Often, putting it in writing reveals the actual disagreement (which is usually smaller than it felt). Invite a third senior or skip-level to weigh in. If still unresolved: scope a 2-week timeboxed PoC for each position; measure agreed criteria. The one who's wrong learns; both gain credibility. As the lead, you make the final call if needed, but visibly only after exhausting the structured options. Document the decision and rationale in an ADR. Don't let it sit — unresolved tech disputes corrode trust faster than wrong decisions.

40.5 References

41Incident & Postmortems

41.1 The Incident Cycle

  1. Detect — alerting; ideally before users notice.
  2. Triage — severity, ownership, comms channel.
  3. Mitigate — feature flag off, rollback, scale up.
  4. Communicate — internal + external updates on cadence.
  5. Resolve — full recovery.
  6. Postmortem — blameless, action items, follow-through.

41.2 The Blameless Postmortem

Inspired by Etsy and SRE: focus on systems and process, not individuals. Output: timeline, contributing factors, blast radius, what worked, what didn't, action items with owners and dates.

41.3 Hard Questions

A frontend regression caused 30 minutes of broken checkout. Walk through your postmortem.
Model: Timeline first — every event with timestamp and source. Contributing factors (not "root cause" — there's never one): test gap, deploy automation gap, monitoring gap, communication gap. What worked: rollback was fast, on-call responded in 3 min. What didn't: PR review missed the issue; bundle-size budget didn't catch the regression because it was logic, not size; CWV alerting was too lenient. Action items: (1) add specific test for the broken flow, (2) add canary % traffic check before full rollout, (3) tighten alerting threshold to 2× p75 deviation, (4) blameless write-up shared in #incidents and #engineering. No "punish the engineer who shipped it" — the system let them. Follow up in 1 month on action items.

41.4 References

42Behavioral & Storytelling

42.1 The STAR Structure

  • Situation — concise context.
  • Task — what you owned.
  • Action — specific things you did (not "we").
  • Result — quantified outcome + lesson.

42.2 Story Bank — Prepare 6-8 Stories Covering

  • A time you led a difficult technical decision (push back on senior leadership).
  • A time you disagreed with a peer and worked through it.
  • A failure — what you learned.
  • A migration or refactor you led.
  • A time you mentored someone significantly.
  • A production incident you owned.
  • A scope cut you pushed for.
  • A time you said no to a stakeholder.

42.3 Amazon Leadership Principles (relevant beyond Amazon)

  • Customer Obsession · Ownership · Invent and Simplify · Are Right, A Lot · Learn and Be Curious · Hire and Develop the Best · Insist on the Highest Standards · Think Big · Bias for Action · Frugality · Earn Trust · Dive Deep · Have Backbone; Disagree and Commit · Deliver Results.

42.4 Hard Questions

Tell me about a time you were wrong technically and a teammate corrected you.
Strong answer shape: Specific situation. Your initial position (with reasoning). What the teammate showed you. How you updated — including any humbling moments. The outcome. The lesson (something you do differently now). Avoid: pretending the disagreement was minor, claiming you were "actually right in some sense," or framing it as you teaching them. Lead-level engineers are good at being wrong gracefully — interviewers calibrate on this.

43Hard Questions Bank — Rapid-Fire

A scrollable pool of 60+ hard questions across all areas. Sprinkle through the interview; never ask all of them.

43.1 Core Web

  1. Explain the rendering pipeline. Where is the bottleneck in a typical SPA?
  2. Walk through what happens when you type a URL and hit Enter.
  3. What's the difference between the DOM and the render tree?
  4. Why is animating transform cheaper than top?
  5. How does the browser decide what's a compositing layer?
  6. What's a forced synchronous layout? How do you detect it?
  7. What does requestAnimationFrame do that setTimeout doesn't?
  8. Why are passive event listeners important for scroll performance?

43.2 JavaScript & TypeScript

  1. Implement Promise.all from scratch. Now Promise.allSettled.
  2. Implement a debounce. Now a leading-edge throttle.
  3. Write a curry function. Now a pipe function.
  4. Explain prototype chain vs class inheritance.
  5. What's the iteration protocol? Build a custom iterable.
  6. Implement deep clone without structuredClone.
  7. Write an LRU cache.
  8. Explain generators and how they enable async iteration.
  9. Type a generic pick function with key inference.
  10. Build a discriminated union for an API response.

43.3 React

  1. Why are hook calls order-sensitive?
  2. Implement useDebouncedValue.
  3. Implement useEventCallback (stable identity, latest closure).
  4. What does useTransition do? Give a concrete example.
  5. How does React decide a component should re-render?
  6. What's the difference between useMemo and useRef?
  7. When is useEffect the wrong tool? What's right?
  8. Explain selective hydration.
  9. What can a Server Component not do?
  10. Why is React Compiler important for INP?

43.4 Performance

  1. LCP regressed from 2.0s to 3.5s overnight. No deploys. Investigate.
  2. Bundle is 600 KB. Cut to 200 KB. How?
  3. INP is 600 ms on mobile. Plan.
  4. Explain Long Animation Frames vs Long Tasks.
  5. How do you set up a performance budget that actually blocks PRs?
  6. Why is preconnect different from preload?
  7. What does HTTP/2 give you that HTTP/1.1 didn't?
  8. Walk me through optimizing TTFB for a Next.js app.

43.5 Security

  1. Walk through OAuth 2.1 with PKCE end-to-end.
  2. Difference between XSS and CSRF — defenses for each?
  3. What's the danger of localStorage for tokens?
  4. How would you implement a strict CSP for a React app?
  5. Explain Trusted Types.
  6. What's Subresource Integrity, when does it fail?
  7. Walk through threat-modeling a "share via link" feature.

43.6 Architecture & System Design

  1. Design a news feed for 50M MAU.
  2. Design Google Docs-style collaborative editor.
  3. Design an autocomplete for a search engine.
  4. Design a video player with adaptive bitrate.
  5. Design Slack's chat client.
  6. Design a company-wide design system used by 50 teams.
  7. Design infinite scroll with 100k items.
  8. Walk through micro-frontends — when, why, and the gotchas.
  9. Module Federation in production: name three problems and the fixes.
  10. How do you cache-invalidate across CDN + SW + client cache?

43.7 Leadership

  1. Tell me about a technical decision you reversed.
  2. How do you raise the bar without breaking team velocity?
  3. Walk me through a migration you led.
  4. An engineer keeps shipping 1500-line PRs. What do you do?
  5. Your team is burned out. How do you address it?
  6. Two senior engineers disagree on architecture. How do you resolve?
  7. Tell me about a failed project. What did you learn?
  8. How do you decide what tech debt to pay down first?
  9. How do you mentor someone into senior?
  10. What's your hiring bar? Defend it.

44Reference Library

Curated authoritative sources. Bookmark these.

44.1 Specs & Standards

44.2 Engineering Blogs

44.3 People to Follow

44.4 Performance & Web Vitals

44.5 Architecture & System Design

44.6 Tools (canonical docs)

44.7 Books

  • "High Performance Browser Networking" — Ilya Grigorik (free online)
  • "Designing Data-Intensive Applications" — Martin Kleppmann
  • "Refactoring" — Martin Fowler
  • "You Don't Know JS" — Kyle Simpson (free on GitHub)
  • "Inclusive Components" — Heydon Pickering
  • "Atomic Design" — Brad Frost (free online)
  • "Staff Engineer" — Will Larson
  • "The Manager's Path" — Camille Fournier
  • "Accelerate" — Forsgren, Humble, Kim (DORA)
  • "An Elegant Puzzle" — Will Larson

44.8 Newsletters Worth Subscribing

44.9 Closing Note

This guide is a living artifact. The web platform shipped more in the last 3 years than in the prior decade — and the pace is accelerating with AI integration. The Lead Frontend Developer in 2026 is, more than anything else, an engineer with opinions backed by evidence, who reads first sources, ships small often, and builds teams that outlive their tenure. Use this guide to calibrate, not to memorize.

45Market Reality — What Top Companies Actually Hire For

Distilled from 2026 Senior/Lead Frontend Engineer job descriptions at Airbnb, Anthropic, Vercel, Netflix, Uber, Stripe, Meta. Use this to calibrate what really matters.

45.1 The Universal Bar (in every JD)

  • 5+ years of professional experience; 2+ years on consumer-facing or production-scale apps.
  • Deep React + TypeScript — table stakes, not differentiator. Advanced TS (generics, conditional types, discriminated unions) explicitly mentioned.
  • Core web fundamentals — HTML semantics, CSS layout, browser internals, network protocols. Not assumed; tested.
  • Performance ownership — Core Web Vitals literacy, real-user monitoring, perf budgets.
  • Accessibility — WCAG 2.2 AA mentioned in every senior+ JD post-EAA (June 2025).
  • Testing strategy — not just "writes tests" — owns testing philosophy across unit/integration/E2E.
  • System design ability — verbal walkthrough of large frontend architectures.
  • Collaboration evidence — cross-functional with design, product, backend, infra.

45.2 Company-Specific Emphasis Patterns

CompanyWhat they weight heaviestDistinctive ask
AirbnbSystem design & cross-team work; design system literacyGraphQL + networking platform; design-language consistency across 50+ surfaces
AnthropicAI/LLM product UX, streaming UIs, RSC mastery; deep React 19+Building agent interfaces; tool-call rendering; safety-aware UX
VercelNext.js App Router internals; Edge runtime; perf at scaleRSC, streaming SSR, framework contribution mindset
NetflixSystem design (highest weight); behavioral fit; project deep-diveMedia/video streaming UX; A/B experimentation discipline; minimal coding-puzzle focus
UberCoding (CodeSignal OA), DSA fundamentals, then system designReal-time / map-heavy UX; high-scale dispatch UI
StripeAPI ergonomics; developer experience; correctnessForms, money, type-safe end-to-end; long PR review culture
MetaRelay/GraphQL, custom infra, scaleOwns parts of React itself; expects RFC literacy
FigmaCanvas, WASM, CRDT, low-latency collabRenders at 60fps under multiplayer load
LinearLocal-first architecture; sync engines; perceived instantnessOptimistic UI, IndexedDB, custom state engine
NotionDocument editing, schemas, collaborative stateBlock-based editor architecture; performance at large doc sizes
ShopifyStorefront perf (Hydrogen), CSS-in-JS replacement, edge SSRMulti-tenant theming; Remix/RR7 ecosystem

45.3 The Hidden Bar — What Senior Means in 2026

From Noor Mohamad — Six FE Capabilities (May 2026) and MockExperts — FE Engineering 2026:

  1. Rendering pipeline literacy — explain LCP and CLS from the browser's perspective, not from Lighthouse output.
  2. Network & performance optimization — at the same depth a backend engineer understands DB indexing.
  3. Server vs client boundary for RSC — knowing what runs where, why, and the perf consequence.
  4. Architectural opinion — Module Federation vs single-spa vs iframe; defend a position.
  5. Testing as a system — pyramid shape, flake management, what to skip.
  6. Product judgment — pushing back on requirements that hurt users.

45.4 What "Lead" Adds on Top of Senior

  • RFC / ADR authorship — written communication is the leverage point.
  • Cross-team influence without authority.
  • Mentoring 2–4 engineers with measurable growth.
  • Migration leadership — bringing a team off a deprecated stack without melting velocity.
  • Incident command experience — has run a production incident as IC.
  • Hiring contributions — interview loop owner, candidate calibration sessions.

45.5 Decoded — How to Read Between the JD Lines

JD phraseWhat it actually means
"Own the technical roadmap"Expect 30% time on RFCs and 1:1s, not coding.
"Work in ambiguity"Product hands off vague problems; you scope, prioritize, ship.
"High leverage"Building platforms others use, not features users see directly.
"Production-grade"Observability + on-call + perf budgets baked in from day 1.
"Bias for action"Ship a prototype this week, not a design doc this month.
"Raise the bar"Your hiring decisions and code reviews carry weight beyond your own work.
"Customer obsession"You read user research; you sit with the support inbox monthly.

45.6 References

46Staying Current — A Sustainable Learning System

The field shipped more in the last 3 years than the prior decade. The signal you can keep up — not that you already know it — is what gets you hired and keeps you employable.

46.1 The Layered Learning Routine

CadenceWhat to doTime
Daily (15 min)Skim a curated newsletter or RSS feed; star one item to read deeply later~15 min over coffee
Weekly (1–2 hr)Read one deep technical article from a starred queue; try one new library/feature in a sandboxFriday afternoon or weekend
Monthly (3–4 hr)Build a small project with one new tech you've been curious about; write a 1-page brief on what you learnedOne Saturday
QuarterlyAudit your toolkit — what to drop, what to add; attend or watch one conference2-day block
YearlyPick one "stretch" topic outside daily work (compilers, ML, systems, DBs) — depth over breadthDedicated 20% time

46.2 Daily — Newsletters & RSS

Curate ruthlessly. Subscribing to 30 newsletters is the same as zero — you'll mark them read without reading.

46.3 Weekly — Deep-Dive Sources

46.4 Communities Worth Joining

  • Twitter/X — still where new releases break first. Curate aggressively; mute liberally.
  • Bluesky — increasingly where web standards / React people are migrating.
  • Reactiflux Discord — React-focused community.
  • r/reactjs, r/javascript, r/typescript, r/webdev, r/ExperiencedDevs.
  • Hacker News — discover; don't doom-scroll.
  • Local meetups — Meetup.com, LeadDev events, framework-specific.

46.5 Conferences to Watch (recordings are free)

46.6 Podcasts (commute material)

46.7 Long-Form & Books (quarterly)

See Section 44.7 — Books. Build a 2-books-per-quarter habit; mix one technical (e.g., DDIA) with one leadership (e.g., Staff Engineer).

46.8 The "Read on Schedule" Stack

Set up an RSS reader (Feedly, Inoreader, Reeder). Subscribe to engineering blogs (Section 44.2), newsletters, GitHub release feeds for libraries you use. Read for 15 min daily; never let the queue build past 100.

46.9 Track What You Learn

Keep a personal "learning journal" — a markdown file, an Obsidian vault, a Notion page. One entry per learning, ~3 sentences: what, why it matters, link to source. After a year you'll have 200+ entries — interview gold, promotion packet evidence, blog-post seed material.

The compounding rule: 30 min/day × 5 days = 130 hours/year of curated learning. That's a degree-level investment hidden in the cracks of a normal job. The candidates who do this stand out at every interview without trying.

47Practice Platforms & Exercise Bank

Reading about interviews ≠ being ready. Practice with the same intensity and structure you'd practice a musical instrument.

47.1 The Top Practice Platforms (2026)

PlatformStrengthsBest for
GreatFrontEnd500+ questions, in-browser code, prep plans, ex-FAANG authorsEnd-to-end FE interview prep; system design + coding combined
FrontendLead300+ practice questions; company-specific filters (Netflix, Uber, Stripe)Targeting a specific company; system-design walkthroughs
BFE.devJS/React quizzes with auto-graded tests; daily challengesSharpening JS internals (implement Promise, debounce, deep clone)
FE Interview HandbookFree, structured, comprehensive; now part of GreatFrontEndStarting point; foundational concepts
PrampFree peer-to-peer mock interviewsLive practice with another candidate — invaluable
interviewing.ioAnonymous mock interviews with FAANG engineers (paid)High-stakes mock with detailed feedback
LeetCodeDSA + occasional frontend; Uber-style OAsCodeSignal/HackerRank-style screens
CodeSignalUsed by Uber, Meta, others for OAsFamiliarize with the actual platform
HackerRankFrontend skills tracksAlgorithmic warm-up
Frontend MastersVideo courses on advanced topicsFilling specific gaps — RSC, accessibility, perf
Epic React (Kent C. Dodds)Workshop-style React deep-diveSolidifying React fundamentals + advanced patterns
Total TypeScript (Matt Pocock)Interactive TS exercisesLeveling up the type system

47.2 Curated Practice Problems by Level

Warm-up (30 min each)

  • Implement debounce, throttle, memoize, curry.
  • Implement Promise.all, Promise.allSettled, Promise.race, Promise.any.
  • Deep clone an object (without structuredClone); flatten a nested array; group by.
  • Implement EventEmitter / pub-sub.
  • LRU cache.
  • String compare with version semantics (1.2.10 vs 1.2.2).

Component-level (45–60 min)

  • Build an autocomplete with debounce, cancellation, keyboard nav, ARIA.
  • Build a virtualized list (no library).
  • Build a modal with focus trap, ESC, click-outside, restore focus.
  • Build a multi-step form wizard with URL state per step.
  • Build infinite scroll using IntersectionObserver.
  • Build a star-rating component (controlled + uncontrolled).
  • Build a sortable / draggable list (mouse + keyboard).
  • Build a tabs component with the Compound pattern + ARIA.
  • Build a tooltip that auto-positions (collision detection).
  • Build a video player with custom controls + captions toggle.

Mini-app (90–120 min)

  • Pokemon / Starwars API explorer (from your existing probe exercises).
  • Tic-tac-toe → Connect 4 → Chess board (UI only).
  • Real-time stock ticker (WebSocket / SSE).
  • Kanban board with drag-drop and persistence.
  • Markdown previewer with syntax highlighting.
  • Pomodoro timer with persistence + notifications.
  • Reddit-style nested comment thread.

System design (45–60 min verbal)

  • Twitter / X feed.
  • Slack / chat client.
  • Google Docs / collaborative editor.
  • Autocomplete (Google search bar).
  • Photo sharing (Instagram-like).
  • Video streaming UI (Netflix-like).
  • E-commerce checkout flow.
  • Email client.
  • Stock trading dashboard.
  • Multi-tenant admin dashboard.

47.3 The 6-Week Interview Sprint Plan

Week 1 — Foundations

Audit + plan

Take 3 BFE.dev quizzes, 2 GreatFrontEnd questions, 1 system design problem. Identify weak areas. Write a learning plan with 2 weak areas per week.

Week 2 — JS & React core

Deep-dive on closures, async, hooks internals

5 BFE.dev/day implementing language primitives. Re-read React docs hook by hook. Build one component-level exercise.

Week 3 — Components & patterns

Build 5 component exercises end-to-end

Build with full a11y, error states, loading. Record yourself explaining the build (record your screen).

Week 4 — System design

3 verbal system designs with the RADIO framework

News feed, autocomplete, chat. Time-box 45 min each. Record audio; play back; cringe; iterate.

Week 5 — Mocks

Schedule 2 Pramp + 1 paid interviewing.io

Get external feedback. Fix the top 2 issues each mock identifies before the next.

Week 6 — Behavioral + polish

STAR-format 8 stories; review communication snippets

Record yourself answering "tell me about a time" prompts. Tighten openings, prune tangents, end with measurable outcomes.

47.4 Build a Visible Portfolio Project

One real project under your GitHub beats five toy exercises. Pick a real problem; ship to production; write a 2-page README that includes:

  • Problem statement (one paragraph).
  • Architecture diagram.
  • Trade-offs you considered and the one you picked, with rationale.
  • Performance budget + measured results (Lighthouse / RUM).
  • Accessibility audit (axe / Lighthouse).
  • What you'd do differently.

This becomes the "tell me about a project" anchor in every interview.

47.5 References

48Technical Communication Snippets — Sound Like a Lead

Memorize these. They are the verbal scaffolding that makes ordinary technical content sound like senior-engineer reasoning. Use the exact phrases; over time they become natural.

How to use this section: Pick 8–10 phrases that match your weak moments (when you freeze, when you ramble, when you don't know). Practice each one out loud 10 times. Within a week they become reflexive — and your interviewer reads "calm and senior" instead of "nervous and junior."

48.1 Opening a Coding Problem

The first 60 seconds set the tone. Never start typing. Always restate + clarify + plan.

After the interviewer states the problem
"Thanks. Let me make sure I understand correctly — you'd like me to build [X] that does [Y]. Before I dive in, I have a couple of clarifying questions. Is that okay?"
Asking about scope
"Quick clarification — what's the scope here? Should I focus on the happy path first and then come back to edge cases, or should I handle errors and loading states up front?"
Asking about constraints
"A few constraints I want to confirm: do we care about accessibility? Mobile? Should this work without JavaScript? Any rough idea of data volume — are we looking at hundreds of items or hundreds of thousands?"
Asking about input/output shape
"What does the API response look like? Can you give me a sample shape? And what format do you expect the final result in?"
Before coding, share your plan
"Here's my approach: I'll start with [step 1], then move to [step 2], and finally tackle [step 3]. The trickiest part is probably [X] — I'll talk through it when I get there. Does that approach sound reasonable, or would you prefer I start somewhere else?"

48.2 Talking While Coding

Silent coding feels long to the interviewer. Narrate your thought process — but only the non-obvious parts.

Explaining a decision
"I'm using useState here rather than useReducer because the state is simple — one boolean. If this grew to three or four interrelated fields, I'd probably switch."
Acknowledging trade-offs in real time
"I'm taking a shortcut here for clarity — in production I'd extract this into a custom hook so it's reusable. Let me know if you'd like me to refactor it now or come back to it."
When you're about to do something unusual
"This pattern might look strange — let me explain why. [Reason]. The trade-off is [trade-off]. Happy to use a more conventional approach if you'd prefer."
Pausing to think
"Let me think for a moment — I want to get this right." (Silence for 10–15 seconds is fine. Don't fill it with nonsense.)
Spotting your own bug
"Wait — I think there's a subtle issue here. If [scenario], this would [problem]. Let me fix that." (Showing you catch your own bugs is a strong signal — don't hide it.)

48.3 When You Don't Know Something

"I don't know" delivered confidently is one of the strongest signals. Faking knowledge is the fastest way to fail.

Honest "don't know" with curiosity
"I haven't worked with that directly. My understanding is roughly [whatever you know] — but I want to be upfront that I'd verify this before relying on it. Is that the right direction, or am I off-base?"
"Don't know" + reasoning attempt
"I don't know the specific answer, but I can reason about it. From first principles, I'd expect [logical guess], because [reasoning]. I'd want to test that before claiming certainty."
Pivoting to adjacent knowledge
"I haven't used [X] specifically, but I've worked with [Y] which solves a similar problem by [approach]. Would that perspective be useful here?"
Asking to skip and come back
"Honestly, I'd be guessing on this one. I'd rather we move to something I can speak to with confidence — and if there's time at the end, I can take another swing at this."

48.4 Explaining Trade-offs (the Lead Signal)

The single most under-used phrase in interviews. Use "trade-off" 5+ times per interview.

The general trade-off frame
"There are two ways to approach this. Option A is [X] — that gives us [benefit], but at the cost of [downside]. Option B is [Y] — better on [dimension], worse on [other dimension]. I'd default to A here because [context-specific reason], but I'd reach for B if [condition]."
When asked "which is better?"
"There isn't a universally better answer — it depends on [factor]. For our case, I'd lean toward [choice] because [specific reason]. If [condition were different], I'd switch."
Comparing libraries / approaches
"[Library A] is more mature and has the ecosystem advantage. [Library B] is lighter and has better DX for our specific use case. The deciding factor for me would be [criterion] — if we expect [scenario], I'd pick [A]; otherwise [B]."
Discussing your previous decision
"At the time, we chose [X] because [reason]. Looking back, I think we'd make a different call today — [Y] is more aligned with where the ecosystem went. That said, the original decision wasn't wrong given what we knew."

48.5 Handling Pushback or Disagreement

Lead candidates are tested on whether they can be challenged without crumbling — and without dying on the hill.

When they push back gently
"That's a fair point — I hadn't considered [X]. Let me think about that. [Pause.] Yes, I think you're right — in that case, [revised approach] makes more sense."
When you still believe your approach
"I hear you. The reason I'd still lean toward [my approach] is [reasoning]. But I see the case for [their approach] — what would you weight more heavily in this scenario?"
When you're definitely wrong
"You're right — I was wrong about [specific thing]. Thanks for catching that. Updating my mental model: [corrected statement]."
When pushed into a corner you don't agree with
"I want to push back on that gently — in my experience, [counter-evidence]. But I'm curious what you've seen — is there context in your environment that would make me reconsider?"

48.6 Wrapping Up an Answer

Bad answers trail off. Good answers land.

Landing the answer cleanly
"So to summarize: [point 1], [point 2], and the trade-off being [trade-off]. Let me know if you'd like me to go deeper on any of those."
When you've talked too long
"Sorry, I'm going on a bit — the short answer is [3-sentence summary]. Happy to expand on any specific area."
Inviting a deeper question
"That's how I'd approach it at a high level. There are a few areas I deliberately glossed over — [list]. Would you like me to dive into any of those?"

48.7 System Design Interview Phrases

Starting a system design
"Before I dive into architecture, I want to make sure I understand the requirements. Let me ask a few clarifying questions and then state assumptions out loud."
Stating assumptions
"Based on what you've said, I'm going to assume: [assumption 1], [assumption 2], [assumption 3]. If any of these are wrong, please stop me."
Structuring the answer
"I'll walk through this in four parts: high-level architecture, data model, the API and component interface, and then optimizations. I'll spend most time on the parts most relevant to your team — let me know if I should reweight."
Drawing without a whiteboard (over Zoom)
"Let me describe the architecture as if I were drawing it: imagine three boxes — client, BFF, services. The client talks to the BFF over [X]. The BFF aggregates and caches before hitting services. Let me know if that's clear or if you'd like me to share my screen and sketch it."
Showing you'd considered scale
"At small scale, [approach A] is fine. The interesting question is what changes when we hit [scale point] — at that point, I'd reach for [approach B] because [reason]. Want me to focus on the small-scale design or the scaled-up version?"
Acknowledging what you'd defer
"For time, I'm deferring [topic] — I'd want to spend real time on it in a follow-up. The headlines: [2-sentence summary]. Happy to come back if there's time."

48.8 Behavioral (STAR) Phrases

Opening a STAR story
"Sure. Let me give you a recent example. About [X months/years] ago, I was leading [project] at [company]. The situation was [one-sentence context]."
Stating your specific role
"My role specifically was [X]. I wasn't responsible for [Y] — that was [other person/team] — but I owned [specific scope]."
Describing your action — use "I" not "we"
"What I did was — first I [action 1]. Then I [action 2], because [reasoning]. The thing I'm most proud of is [specific decision], because most engineers would have [common path] but I [different path]."
Closing with quantified outcome
"The outcome was [measurable result]. Concretely — [number]. The thing I took away for next time was [lesson]."
When asked "tell me about a failure"
"I'll give you a real one — not a brag-disguised-as-failure. [Specific failure, no hedging.] What happened was [factual sequence]. What I'd do differently now is [concrete change]. I've actually applied this lesson since — [example]."
When asked about conflict
"There was a real disagreement with [role, not name]. They believed [their position]; I believed [my position]. We worked through it by [process — usually: writing it down, getting a third opinion, time-boxing a PoC]. We landed on [resolution]. I learned that [meta-lesson about working with people]."

48.9 Questions to Ask the Interviewer (End of Loop)

Asking good questions is half the interview signal. Have 5–6 prepared; pick based on what you've heard.

About the role & team
"What does the first 90 days look like for someone in this role? What does a successful first 6 months look like — and what does failure look like?"
About engineering culture
"How are technical decisions made on your team? When engineers disagree, what's the process? Can you give me a recent example?"
About growth
"For someone at this level, what's the path to the next level here? What do the engineers who get promoted do that others don't?"
About debt & reality
"What's the single biggest piece of tech debt the team is carrying? What would you ship tomorrow if you had unlimited capacity?"
About process
"How do you measure engineering effectiveness on the team? Do you track DORA metrics or something else?"
About the interviewer themselves
"What's the best decision your team has made in the last year? What's a decision you'd want to revisit?"
When the answers will tell you a lot
"What's the on-call experience like? When was your last production incident — and what happened in the postmortem?"

48.10 Confidence-Building Verbal Hygiene

ReplaceWithWhy
"I think maybe…""My initial take is…" or "I'd lean toward…"Sounds tentative without sounding hedgy
"This is probably wrong, but…""Here's my best thinking…"Don't pre-undermine yourself
"Does that make sense?""Did I answer your question?" or "Want me to go deeper anywhere?"The first sounds insecure; the second invites engagement
"I'll try to…""I'll…"Eliminate hedge verbs
"Sorry, just one more thing…""One more point worth adding…"No apologies for adding value
"I'm not an expert but…"(omit entirely)The interviewer didn't ask for credentials
"Um", "like", "you know"Silence2 seconds of silence sounds confident; "umm" sounds nervous
Uptalk (rising intonation on statements)Declarative downward toneStatements should sound like statements

48.11 Quick Rehearsal Drills

  • Mirror drill — answer 3 behavioral questions out loud to your mirror, twice a week. You'll instantly hear filler words.
  • Recording drill — record yourself answering a system design question. Play back at 1.5× speed; the awkward moments compress into obvious patterns.
  • 2-sentence drill — every technical concept you know, write a 2-sentence explanation. Forces compression. (Try: hydration, CSP, useMemo, RSC, INP.)
  • Trade-off drill — every time you read about a tech, write down its trade-offs vs the alternative. After a month, this is reflexive in conversation.
  • "Why" drill — when someone explains a decision to you, ask "why" 3 times. Then practice answering 3 levels deep on your own decisions.

48.12 References

49Mock Interview Drills — Self-Practice Routines

Solo practice beats no practice. Structured solo practice beats unstructured group practice.

49.1 The Daily 45-Minute Routine

BlockTimeWhat
Warm-up5 minOne BFE.dev problem — implement a primitive
Coding20 minOne component-level exercise, talking out loud (no music, no silence)
System design15 minVerbal walkthrough of one design problem, with timer; record audio
Reflection5 minWatch/listen back to one moment; note one phrase to improve

49.2 The Weekly Mock

Once a week, do a full 45–60 minute mock with someone else. Options:

  • Pramp — free peer matches; reciprocal practice.
  • interviewing.io — paid mocks with ex-FAANG engineers.
  • A friend in the industry — trade mocks; honest feedback > polite feedback.
  • An AI mock — use Claude / ChatGPT to role-play the interviewer; surprisingly effective for behavioral practice.

49.3 The Recording Loop (the highest-ROI drill)

  1. Pick a problem. Set a 45-minute timer.
  2. Talk it out loud as if interviewer is in the room. Record screen + audio.
  3. Stop at 45 min regardless of completion.
  4. Watch it back at 1.5× speed.
  5. Note 3 specific things — one verbal habit, one missed concept, one structural issue.
  6. Pick one to fix; redo the next day.

If you do this 3× a week for a month, your interview self is unrecognizable from your start point. Recording is uncomfortable; do it anyway.

49.4 The Behavioral Story Workshop

  1. Make a list of 8 stories from your career (use Section 42.2 categories).
  2. For each, write a STAR outline (4 bullets, max 200 words).
  3. Practice each out loud — target 90 seconds for "tell me about a time" answers.
  4. Time yourself; if you exceed 2 minutes, you're rambling. Trim.
  5. Get a friend to ask follow-ups — "what specifically did you do?", "what was the metric?" — to stress-test your answer's specifics.

49.5 The AI Rubber-Duck Loop

Use Claude or ChatGPT as a relentless follow-up generator. Prompt template:

You are a senior frontend engineer interviewing me for a Lead role.
Ask me [X — e.g., a system design question for "design Twitter feed"].
After my answer, ask 3-5 follow-up questions that probe weak spots.
Be tough but constructive. Do not give answers — only ask.

The AI will probe corners you didn't anticipate. Better than a friend who doesn't know the domain; cheaper than a paid mock.

49.6 The "Explain to a Junior" Drill

For every concept you intend to discuss in an interview, prepare two versions:

  • 30 seconds — what it is, why it matters, one example.
  • 3 minutes — the same plus trade-offs and one war story.

If you can't compress to 30 seconds, you don't understand it yet. Compression is mastery.

49.7 The Failure-Mode Calendar

Track your interview attempts in a simple table:

DateQuestionWhat I did wellWhat brokeFix for next time
Apr 14Build autocompleteAsked clarifying QsForgot ARIA combobox roleRe-read APG combobox; do 1 more autocomplete
Apr 16Design news feedRADIO structureGlossed over caching; got corneredRe-read CDN section; rehearse cache-invalidation answer

This becomes your personalized weakness map.

49.8 Mock Interview Templates to Run Yourself

Template A — JS / TS warm-up (15 min)

  • Implement a debounce with cancel.
  • Type a generic pick function with full key inference.
  • Explain a stale closure and how you'd fix it.

Template B — Component build (45 min)

  • Build an accessible modal with focus trap.
  • Discuss state management choice mid-build.
  • Add keyboard handling under interviewer probe.

Template C — System design (45 min)

  • Run RADIO end-to-end on a feed/chat/editor problem.
  • Force yourself to draw (paper or whiteboard).
  • Stop at 45 min — even mid-thought.

Template D — Behavioral (30 min)

  • 5 rotating prompts: failure, conflict, leadership, mistake, scope-cut.
  • Limit each answer to 90 seconds.
  • Self-grade: did you say "I" or "we"? Specific or vague? Quantified outcome?

50Communication Anti-Patterns — What Kills Interviews

Even strong engineers tank interviews on these. Most are habits you can break in 2 weeks of deliberate practice.

50.1 The Top 10 Killers

  1. Silent coding. The interviewer can't read your mind. 5 minutes of silent typing reads as "doesn't know what they're doing."
  2. Diving in without clarifying. Skipping requirements is the #1 reason senior candidates get downleveled. Spend 3–5 minutes asking.
  3. Saying "we" instead of "I". Behavioral round killer. Interviewers explicitly listen for "I" — they want to know your contribution.
  4. Rambling. Hard cap your answers at 2 minutes; pause and ask "want me to keep going?"
  5. Pretending to know. Always fails. Interviewers ask exactly the question they know you don't know to test honesty.
  6. Defending a wrong answer to the death. Showing you can update is more important than being right.
  7. Not asking any questions back. Reads as low curiosity. Always have 5 prepared.
  8. Filler-word storms. "Um", "like", "kind of", "sort of", "basically" — each one chips at your authority.
  9. Pre-undermining. "This is probably wrong but…" — never. State your answer; let them judge.
  10. Tangents. Answering a different question than the one asked. Listen to the actual question; answer the actual question.

50.2 Body Language & Presence (Video Interview)

  • Camera at eye level — not below, not above. Stack books under your laptop.
  • Look at the camera when delivering a key point, not at the screen.
  • Lighting in front of you, not behind — face a window, not back to one.
  • Quiet background — no notifications, phone on silent in another room.
  • Sit up, hands visible — slouching reads through camera.
  • Smile in the first 10 seconds — it sets the room temperature.
  • Don't read from notes mid-answer — eye drift is obvious. Notes for question prompts only.

50.3 The "Sound Senior" Vocabulary Substitutions

Junior phrasingSenior phrasing
"It's hard to say""It depends on the trade-off between X and Y"
"This is easy""There are a few subtle points worth being explicit about"
"I've never done that""I haven't worked with that directly, but the principle I'd apply is…"
"I would probably…""My default would be… unless [condition]"
"Just"(remove) — "just" minimizes complexity and signals naïveté
"Obviously"(remove) — if it were obvious, they wouldn't ask
"Quickly""Concisely" / "at a high level"
"I feel like""My read is" / "the evidence suggests"
"Sorry"(reserve for actual mistakes; don't reflex-apologize)

50.4 Specific Failure Modes to Train Away

The Tangent Spiral
Signal: Your sentence ends with the topic 5 hops from where you started. Fix: Build a "topic anchor" habit. Before each new sentence, mentally check: "does this serve the question they asked?" If no, stop.
The Apology Loop
Signal: "Sorry, I'm not sure…" "Sorry for the long answer…" "Sorry, let me think…" Fix: Replace with neutral framing: "Let me think about that," "Quick recap before I continue," "I want to be precise here."
The Defensive Shutdown
Signal: Interviewer challenges; you go quiet or defensive. Fix: Train the phrase "That's a fair point — let me think." Use it on every challenge. Buys time and signals security.
The Brain Dump
Signal: They ask one question; you answer 4. Fix: Answer the literal question in 30 seconds. Then ask: "Want me to expand on any of those?" Let them lead the depth.
The Buzzword Wall
Signal: Heavy on terms (microservices, RSC, edge), light on rationale. Fix: Every time you use a term, follow it with "because…" + 1 specific reason or 1 concrete example.

50.5 What to Do If You Freeze

  1. Acknowledge it. "Give me 30 seconds — I want to think through this one." Then actually take 30 seconds. Don't talk through the silence.
  2. State the problem out loud. Restating often unsticks you. "So we need to [X], the constraint is [Y]…"
  3. Reach for first principles. "Let me reason from basics — what does the user need?"
  4. Reach for an analogous problem. "This reminds me of [other problem]. Is the same shape applicable here?"
  5. If still stuck, ask for a hint. "I'm not seeing the obvious path forward. Could you give me a nudge?" — interviewers expect this; using it once is fine.

50.6 Energy & Pacing

  • Match interviewer energy. If they're warm, be warm. If they're terse, be precise.
  • Slow down on important points. Rushing through a key trade-off signals you don't realize it's important.
  • Take water breaks. Sipping water is a legitimate way to buy 3 seconds. Keep a glass in frame.
  • Don't fill silence. 5 seconds feels long to you; sounds confident to them.
  • End on a high note. The last 2 minutes are remembered most. If you stumbled mid-interview, finish strong with a thoughtful question and a clear closing.

50.7 The "Last 10 Minutes" Playbook

  1. If anything went unfinished, address it: "Earlier I said [X] — I want to come back and clarify."
  2. Ask your prepared questions (Section 48.9). Pick 2–3 based on what the conversation revealed.
  3. Show genuine interest in their answers — follow up on at least one.
  4. Express your specific interest: "What you said about [X] is exactly the kind of problem I'd want to work on. I'd love to hear more about that team."
  5. Thank them warmly and concretely — "Thanks for the conversation — I particularly enjoyed the [X] discussion."

50.8 After the Interview

  • Write a thank-you note within 24 hours. 3–4 sentences. Reference something specific from the conversation.
  • Journal what went well and what didn't — while it's fresh. This is your most valuable learning data.
  • Don't replay endlessly. Two passes: one for lessons, one for closure. Then move on.
  • Treat rejection as data, not verdict. A rejection from one company calibrates one signal — not your worth.

50.9 The 30-Day Communication Improvement Plan

Week 1

Awareness

Record yourself answering 3 behavioral and 1 technical question per day. Just listen back — don't edit yet. Note 3 patterns by end of week.

Week 2

Fillers + Apologies

Eliminate "um", "like", "basically", "sorry". Listen for each in playback. Replace with silence or specific phrases from Section 48.

Week 3

Structure

Force every answer into one of three templates: (1) Direct answer + supporting detail, (2) Trade-off frame, (3) STAR. No freeform.

Week 4

Mocks

3 external mocks (Pramp, interviewing.io, or peer). Apply the previous 3 weeks. Collect feedback; revise the worst-rated dimension.

50.10 Final Word

Technical communication is not separate from technical ability — it is a technical ability. Interviewers cannot evaluate what they cannot hear clearly. The strongest engineers you know aren't just smart; they package their thinking so the listener gets it the first time. That packaging is a learnable skill — most engineers never invest in it, which is exactly why investing in it pays disproportionately.

Two weeks of deliberate practice on the snippets, anti-patterns, and drills in Sections 48–50 will move you up half a level in every interview you take. Not because the underlying skills change — because the signal you radiate does.

50.11 References

51JavaScript Core — Everything an Engineer Should Know

Past the syntax. The model. What the engine actually does. Every snippet below is editable and runnable — experiment, break things, change values, hit Run again. This is the section to come back to before any senior interview.

How the code editor works: Each block has a runnable editor. Use console.log() to print. await works at the top level (the code is wrapped in an async function). Click Reset to restore the original snippet. Edits are local to your browser tab — refresh wipes them.

51.1 The Execution Model — Stack, Heap, Queues, Loop

JavaScript is single-threaded with a concurrency model built on the event loop. The runtime has:

  • Call stack — synchronous function frames; LIFO.
  • Heap — where objects live; managed by the GC.
  • Macrotask queuesetTimeout, I/O, UI events, message events.
  • Microtask queue — Promise reactions, queueMicrotask, MutationObserver. Drained completely between every macrotask.
  • Render stepsrequestAnimationFrame callbacks → style/layout/paint → requestIdleCallback.
// Microtask vs macrotask ordering
Tip: await works at top level

// Microtask starvation — a real production bug

References: HTML spec — event loops · Jake Archibald — In The Loop (JSConf.Asia) · Philip Roberts — What the heck is the event loop anyway?

51.2 Closures, Scope & Hoisting

A closure is a function that retains access to its lexical scope after that scope has finished executing. Lexical scope is fixed at write time, not call time. Closures power: data hiding, module patterns, currying, memoization, React hooks themselves.

// Closure mechanics + the loop-var trap

// Module pattern + private state via closure

// Hoisting and the Temporal Dead Zone

Why are closures said to "capture variables by reference, not by value"?
Model: Closures capture the binding — the slot — not the value at the time of capture. That's why a closure inside a var loop sees the final value of i after the loop completes. let/const create a new binding per iteration, which is why each closure sees a different value. This also explains why mutating the captured variable inside or outside the closure is visible on both sides.

51.3 The this Binding

Four precedence rules + one exception for arrows:

  1. new binding — this is the newly constructed object.
  2. Explicit binding — .call(obj) / .apply(obj, args) / .bind(obj).
  3. Implicit binding — method call obj.fn(); this is obj.
  4. Default — undefined in strict mode; global in sloppy.

Arrows have no this of their own — they capture the enclosing lexical this.

// The 4 rules in one snippet

// The "lost this" gotcha + fixes

51.4 Prototypes & Inheritance

Every object has an internal [[Prototype]] pointer (accessible via Object.getPrototypeOf) forming a prototype chain. Property lookups traverse this chain. class is sugar over function prototypes.

// Prototype chain mechanics

// Object.create — prototypal inheritance without classes

51.5 Type System & Coercion Rules

JS has 8 types: string, number, boolean, null, undefined, symbol, bigint, object. Coercion happens with ==, +, -, <, etc. Understanding the rules is the difference between writing code and debugging it.

// Coercion surprises

// IEEE 754 floating-point hell

// NaN — the only value not equal to itself

51.6 Promises & Async Internals

A Promise is a state machine: pending → fulfilled | rejected. Once settled, it never changes. Promise reactions are microtasks. Understanding microtask scheduling explains most async surprises.

// Promise scheduling order

// Promise combinators — when to use each

// Sequential vs parallel awaits — the perf killer

// Cancellation with AbortController

51.7 Iterators & Generators

The iteration protocol underpins for…of, spread, destructuring, Array.from. Generators give you lazy, pausable functions. Async generators stream data.

// Build a custom iterable

// Infinite generator — only computes what you ask

// Async generator — streaming data

51.8 Proxy & Reflect — Meta-Programming

A Proxy intercepts fundamental operations on an object (get, set, has, deleteProperty, etc.). This is how reactivity systems (Vue 3, MobX 6, Valtio) work — and how some bundlers do automatic dependency tracking.

// Reactive object — track reads & trigger on writes

// Default values for missing properties

51.9 Memory — GC, Weak References, Leak Patterns

V8 uses generational GC: young generation (fast Scavenger) and old generation (Mark-Sweep + Mark-Compact). You don't free memory — you stop referencing it.

  • WeakMap, WeakSet — keys held weakly; GC can collect them.
  • WeakRef — hold a reference that doesn't prevent collection.
  • FinalizationRegistry — cleanup hook after GC.
// WeakMap — auto-cleanup metadata keyed on objects

Common leak patterns:
  • Forgotten event listeners on removed DOM nodes.
  • Long-lived closures capturing large objects.
  • Module-level arrays that only grow.
  • Detached DOM nodes still referenced by JS.
  • Timers (setInterval) not cleared on unmount.
  • Subscriptions / observables without teardown.
Diagnose with Chrome DevTools → Memory tab → Heap snapshot + Allocation timeline.

51.10 Symbols & Well-Known Symbols

A Symbol is a unique primitive — used as a hidden / collision-proof property key. Well-known symbols let you customize built-in behavior.

// Customize built-in behavior with Symbols

51.11 Property Descriptors — Below the Dot

Every property has hidden flags: writable, enumerable, configurable, plus either a value (data descriptor) or get/set (accessor descriptor). This is how Object.freeze, const-like read-only behaviour, and computed properties work under the hood.

// Lock down an object with property descriptors

Three levels of immutability:

  • Object.preventExtensions — can't add new properties.
  • Object.seal — above + can't delete or reconfigure.
  • Object.freeze — above + can't modify values. Shallow — nested objects still mutable.

51.12 Modules — ESM, CJS, Dynamic, Top-Level Await

FeatureESMCommonJS
LoadingStatic, async, parallelSynchronous, blocking
ResolutionAt parse timeAt runtime
BindingsLive (read-only views of exports)Copy of the value at require time
Circular depsResolved via live bindings (with TDZ risk)Partial exports possible (gotcha)
Tree-shakableYesNo
Top-level awaitYesNo
// ESM
import { fn } from './mod.js';     // static; tree-shakable
const mod = await import('./mod.js'); // dynamic; code-splitting
export const x = 1;
export default function () {}

// Import maps (browser, Deno, modern bundlers)
<script type="importmap">
{ "imports": { "lodash": "https://esm.sh/lodash-es" } }
</script>
<script type="module">import _ from 'lodash';</script>

// CJS — Node legacy
const { fn } = require('./mod');
module.exports = { fn };

51.13 Numbers, BigInt & Intl

// Intl APIs — locale-aware formatting (built-in, no library!)

51.14 Strings, Unicode & Code Points

Strings are sequences of UTF-16 code units. Most "characters" you care about are code points, some of which take two code units (surrogate pairs). This bites when emoji or non-BMP scripts appear.

// The 🦊 problem — code points vs code units

51.15 Modern Regex

Named groups, lookbehind, the unicode /v flag with set notation, sticky /y for tokenizers.

// Named groups + lookbehind

51.16 Functional Patterns You'll Actually Use

// Currying, partial application, composition

51.17 Error Handling — Beyond try/catch

// Custom errors + Error.cause + AggregateError

51.18 Modern Array Methods — Mutating vs Immutable

MutatingImmutable (ES2023+)
sort()toSorted()
reverse()toReversed()
splice()toSpliced()
copyWithin()with(index, value)
// Immutable array methods + groupBy

51.19 Modern Scheduling APIs

Beyond setTimeout: the Scheduler API gives priority-aware task scheduling. scheduler.yield() is the modern way to break up long tasks for better INP.

// scheduler.postTask (Chrome 94+) — priority-aware

51.20 Lower-Level Topics — Performance, Memory Layout, Engine Quirks

V8 Hidden Classes & Inline Caching

V8 assigns each object a hidden class based on its property layout. Adding properties in the same order to many objects keeps them on the same hidden class → fast. Adding in different orders creates separate hidden classes → slow polymorphic access.

// Initialize all properties in the constructor — same hidden class

Typed Arrays — Contiguous Memory

Regular arrays are sparse object-like. Int32Array, Float64Array, etc. are contiguous fixed-type buffers — 10–100× faster for numeric work.

// Typed arrays + shared memory primitives

Tail Calls, Recursion Limits, Stack Depth

JS engines (except Safari briefly) don't implement proper tail call optimization. Deep recursion blows the stack. Solution: iterative form, or trampoline pattern.

// Stack overflow + trampoline fix

Object Identity vs Equality

JS has four equality semantics: === (Strict Equality), == (Loose Equality), Object.is (SameValue), and SameValueZero (used by Map/Set/Array.includes).

// Four equality semantics

51.21 Interview Classics — Implement From Scratch

These are the most-asked "implement X" questions at FAANG/Anthropic/Vercel. Practice each in the editor; aim to type them from memory.

// Implement debounce with cancel + flush

// Implement throttle (leading + trailing edge)

// Implement Promise.all from scratch

// Implement deep clone (without structuredClone)

// Implement an LRU cache

// Implement an EventEmitter (pub/sub)

// Implement flatten without Array.prototype.flat

// Implement curry (variadic)

51.22 Low-Level Building Blocks for Product Work

Structured Cloning & Transferable Objects

const cloned = structuredClone(complexObject);   // deep clone with cycles, Maps, Dates

// Transferable (zero-copy ownership transfer to a Worker)
const ab = new ArrayBuffer(1024 * 1024);
worker.postMessage(ab, [ab]);     // `ab` is now neutered on this side

SharedArrayBuffer + Atomics (multi-thread shared memory)

Requires Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp. Used by: video editing in browser, WASM threads, audio processing.

BroadcastChannel — cross-tab pub/sub

// BroadcastChannel (works only in a real browser, not this sandbox)

Performance APIs

// High-resolution timing
const start = performance.now();
doWork();
console.log(performance.now() - start, 'ms');

// User Timing API — show up in DevTools Performance panel
performance.mark('checkout-start');
performance.mark('checkout-end');
performance.measure('checkout', 'checkout-start', 'checkout-end');

// PerformanceObserver — listen for long tasks, layout shifts, LCP
new PerformanceObserver(list => {
  list.getEntries().forEach(e => console.log(e.entryType, e.duration));
}).observe({ entryTypes: ['longtask', 'layout-shift', 'largest-contentful-paint'] });

Long Animation Frames (LoAF) — replaces Long Tasks

The successor API for INP debugging. Reports per-frame work + script + render time. web.dev — Long Animation Frames

51.23 Hard JS Questions Asked at Top Companies

Explain how await interacts with the microtask queue. What's the order of execution in async function a() { await b(); console.log('after'); }?
Model: await desugars to a Promise then. The continuation after the await is scheduled as a microtask once the awaited value resolves. So console.log('after') runs in a microtask after b() resolves — meaning all synchronous code after the a() call runs first, then microtasks drain in order.
Why doesn't React batch all state updates by default? When does it batch?
Model: Prior to React 18, batching only happened inside React event handlers. React 18 introduced "automatic batching" — promises, timeouts, native event handlers all batch. The mechanism uses microtask scheduling so updates triggered in the same microtask flush together. flushSync opts out for cases where you need synchronous DOM updates (e.g., before a measurement).
What's the difference between Object.freeze and a deep freeze?
Model: Object.freeze is shallow — nested objects remain mutable. Deep freeze requires recursion: walk own properties, freeze each object value. Watch out for circular references (use a WeakSet). For runtime-enforced deep immutability, prefer libraries like Immer (structural sharing) or persistent data structures (Immutable.js, Mori).
Walk me through how V8 compiles JavaScript. What's Ignition? TurboFan? Sparkplug?
Model: V8 parses to AST → Ignition interprets bytecode (fast startup). Frequently-executed code is profiled and tiered up to Sparkplug (a fast non-optimizing compiler) and TurboFan (the optimizing JIT). TurboFan speculates on observed types; if assumptions break (e.g., a polymorphic call), it deoptimizes back. Implications: warm code is fastest after several executions; megamorphic call sites stay in slow lanes. Reference: V8 — Sparkplug post.
What happens if you throw inside a Promise constructor's executor synchronously vs. asynchronously?
Model: Synchronous throw inside the executor is caught by the Promise machinery and becomes a rejection. Asynchronous throw (inside a setTimeout, for example) is NOT caught — it becomes an unhandled error. The lesson: never throw inside an async callback in the executor; use reject(err) explicitly.
How would you implement useState using only closures and an array?
Model: The simplified mental model: render is a function that calls hooks in order. A module-level array holds slots indexed by hook-call order. Each render resets the index to 0; each useState increments the index and either initializes or reads its slot. Setters capture their slot index in a closure. This explains why hook calls must be ordered consistently across renders — the slot index is positional, not symbolic. (The real React uses a linked list per fiber, not a module array, so each component instance has its own list.)
Explain hidden classes and inline caches in V8. Why do they matter for performance-sensitive code?
Model: V8 tracks the "shape" of every object — its property layout — as a hidden class. Two objects created with the same property assignment sequence share a hidden class. Property accesses get inline-cached based on the observed hidden class. If a call site sees one shape consistently (monomorphic), access is ~1 instruction. With 2-4 shapes (polymorphic), it's slower but still optimized. Beyond that (megamorphic), V8 falls back to a generic lookup. Implications: in hot loops, prefer stable shapes; initialize all props in constructor in same order; avoid delete (transitions to dictionary mode); avoid mixing types in arrays (PACKED_SMI_ELEMENTS > PACKED_DOUBLE_ELEMENTS > PACKED_ELEMENTS > HOLEY_ELEMENTS).

51.24 References for Deep Mastery

How to use this section: Don't read it linearly. Pick one subsection per day; type out each example without copying. Modify the example to break it; predict the new output; run; learn from the surprise. Mastery is built by being surprised and updating your model — not by reading.