Preface
- A High-Level View of Frontend Work
- Book Structure and Outline
- How to Make the Most of This Book
- Summary
Chapter 1 — Evolving from Components to Systems
- Analyzing how simple requests turn complex
- Part I — How a small component grows
- Zooming out to the system perspective
- Developing system design thinking
- A note on CCDAO and the interview lens
- Summary — The invisible work
Chapter 2 — Introducing the CCDAO Framework
- Collecting information for requirement clarity
- Designing modular component structures
- Modeling data for predictability and efficiency
- Designing stable API contracts
- Implementing optimization strategies early
- Applying CCDAO in an Interview
- Why It Matters Beyond Interviews
Chapter 3 — Applying CCDAO: Designing a Typeahead Search Box
- 1. Collect Information
- 2. Component Structure
- 3. Data Modeling
- 4. API Design
- 5. Optimization Strategies
- Closing
Chapter 4 — Applying CCDAO: Designing a Scalable Feed List
- 1. Collect Information
- 2. Component Structure
- 3. Data Modeling
- 4. API Design
- 5. Optimization Strategies
- Closing
Chapter 5 — Data Modeling: Understanding the Domain and the UI
- Defining the domain clearly through business rules
- Designing models for specific UI consumption patterns
- From Domain to Design
Chapter 6 — Case Study: Implementing Sidebar Entitlements
- Step 1 — The Starting Point: Logic in the UI
- Step 2 — When the Rules Multiply
- Step 3 — Moving Business Logic to the Backend
- Step 4 — Where Frontend Logic Still Belongs
- Step 5 — Tailoring APIs with GraphQL or a BFF
- Lessons from the Sidebar
Chapter 7 — Setting Up the Project Environment
- Why We Use a Starter Project
- Prerequisites
- Getting the Project Running
- Useful Scripts
- Configuring the Mock API with MSW
- Mock Endpoints Provided
- Data Shapes You’ll Work With
- Project Structure (High-Level)
- Troubleshooting
- What Comes Next
Chapter 8 — Implementing Data Normalization
- Why Normalisation Matters
- A Real Example: Inconsistent User Data
- Establishing a consistent source of truth
- Transforming nested board payloads into flat tables
- Holding the normalized store in React Context
- Hydrating data during the rendering process
- Summary
Chapter 9 — Drawing Inspiration from Backend Databases
- A Familiar Pattern From Databases
- How Databases Reconstruct Data
- The Frontend Equivalent
- Why This Matters
- A Good Place to Pause
Chapter 10 — Managing Requests and Data Fetching
- Showing Real Assignees in the UI
- Extending the Backend API
- Updating the Board on Selection
- Understanding Race Conditions in Search
- Fixing Race Conditions with Request Cancellation
- Reducing Request Volume with Debouncing and Throttling
- Summary
Chapter 11 — Implementing Pagination Strategies
- Demonstrating Pagination in
UserSelect - The Pagination Strategies
- A Simple Users Table
- Offset Pagination
- Cursor Pagination
- Choosing the Right Strategy for
UserSelect - UI Patterns for Pagination
- Summary
Chapter 12 — Migrating to an Express Backend
- A Brief Introduction to Express
- Setting up a standalone mock API server
- Proxying Frontend Requests to The Express Server
- Summary
Chapter 13 — Implementing Server-Side Rendering
- Rendering strategies
- How SSR works
- Coordinating hydration between server and client
- Creating the client entry (hydration)
- Creating the server entry (rendering on the server)
- Creating separate entry points
- Configuring Vite to build dual entries
- Generating HTML on the server
- Bringing it together in the Express SSR route
- Why consistency matters
- From SSR to SPA behaviour
- Summary
Case Study — Understanding Bundlers Through Code Splitting
- What Problem Are We Solving?
- What a Bundler Actually Does
- Tree Shaking: Removing Unused Exports
- Code Splitting: Deferring Code Until It’s Needed
- A Subtle Caveat: Tree Shaking Stops at Dynamic Boundaries
- What This Case Study Teaches Us
- Summary
Chapter 14 – Implementing Code Splitting and Lazy Loading
- Why Lazy Loading Helps
- The Building Blocks of Lazy Loading
- Implementing Lazy Loading in Our Board Application
- Another Example: Lazy Loading the List View
- Understanding the Build Output After Code Splitting
- What Happens at Runtime
- How Code Splitting Changes the Bundle
- Summary
Chapter 15 – Implementing Data Prefetching
- How Prefetch Works Conceptually
- The Prefetch Function Inside QueryProvider
- Exposing Prefetch Through a Hook
- Prefetching Users in Card.tsx
- How Prefetch and useQuery Work Together
- The Full Runtime Experience
- When Prefetch Helps
- When Prefetch Doesn’t Help
- Summary
Chapter 16 – Implementing Optimistic Updates
- Creating a New Card (Server-First)
- Introducing Optimistic Updates
- Adding a Card Optimistically
- Deleting a Card Optimistically
- Things to Keep in Mind
- Summary
Chapter 17 – Exploring Real-time Update Strategies
- Polling
- Server-Sent Events (SSE)
- WebSockets
- Scaling Considerations
- Summary
Chapter 18 – Implementing Real-time Updates with SSE
- The pub-sub pattern
- Using the pub-sub pattern on the server
- Using the event emitter with SSE
- Emitting events from the update API
- Frontend: consuming SSE with EventSource
- Demonstration and behaviour
- Summary
Case Study — Implementing WebSockets for Real-time Updates
- Server Side — Setting Up WebSockets
- Client Side — Receiving WebSocket Events
- A Real-World Bug: Duplicate Cards
- Making the State Update Idempotent
- Summary
Chapter 19 — Optimizing Performance with HTTP Caching
- Why caching matters
- Cache-Control — how long a response stays fresh
- ETag — detecting whether content changed
- Last-Modified — timestamp-based validation
- Vary — preventing incorrect caching
- Putting it all together: a realistic request flow
- Summary
Chapter 20 — Handling Runtime Errors in React
- A quick comparison to
try/catch - Understanding Error Boundaries
- Wrapping a fragile component
- Cascading error boundaries in a column
- Application-level fallback
- Summary
Chapter 21 — Designing for Accessibility
- Why we need to consider accessibility at all
- Accessibility-first system design principles
- Accessibility checks as part of the testing architecture
- Semantic HTML in real components
- Keyboard navigation as a system concern
- A more complex example: accessible drag and drop
- My typical accessibility workflow
- Summary
Chapter 22 — Implementing Performance Monitoring
- Why performance monitoring matters
- Understanding bundle size in practice
- Making performance limits explicit with budgets
- Measuring real user experience with Web Vitals
- Performance as a continuous system concern
- Summary
The Architectural Roadmap: From Components to Systems
- Module 1: The System Design Mindset (Chapters 1–4)
- Module 2: Building the Data Foundation (Chapters 5–9)
- Module 3: Managing Data Flow and Connectivity (Chapters 10–12)
- Module 4: Rendering and Performance (Chapters 13–15)
- Module 5: Mutations, Real-Time Sync, and Resilience (Chapters 16–22)
- Designing System Step By Step