02 β€” Architectural Mastery

Goal: make foundational decisions deliberately β€” before they become expensive β€” and bootstrap scalable apps (React / Next.js 15 App Router / strict TS) with a repeatable blueprint.

The core principle: Architecture is the set of decisions that are expensive to reverse. Everything else is implementation detail. The job is to identify those decisions, defer the reversible ones, and make the irreversible ones with a written rationale.


Part 1 β€” Mental models (think in these before any decision)

1.1 The reversal-cost lattice

Every decision has a reversal cost. Classify before choosing:

Decision Reversal cost Example
Cheap to reverse Hours–days Component naming, folder layout, hook API, styling approach within a framework
Moderate Weeks State library, data-fetching layer, routing structure
Expensive Months+ Framework choice, monolith vs micro-frontends, server/client rendering paradigm, API contract shape, DB schema exposed to the client

Rule: never spend architectural ceremony on cheap-to-reverse decisions (YAGNI lives here); spend it on expensive ones. If a decision is expensive, write the ADR (01).

1.2 Conway's law, exploited

"Organizations design systems that mirror their communication structure."

The architecture will match your team topology whether you like it or not. Design for the team you have and the growth you expect: if 3 frontend engineers own one app, a modular monolith with clear boundaries beats micro-frontends. If 4 teams must ship independently to one product surface, boundaries (module federation / MFEs / package isolation) become a team problem, not a tech preference. Never adopt micro-frontends for a team that fits one repo β€” you are buying coordination costs you don't have.

1.3 Architecture is a trade-off lattice, not a ladder

Every "best practice" is a trade against something. Use the lattice:

You want You pay Deciding question
Server rendering (SEO, fast first paint) Server cost, cache complexity, hosting constraints Does the page need SEO/linkability or is it an authenticated app?
Client rendering (cheap, simple) Slow first paint, no SEO, weaker perf on low-end devices Is it an internal tool / app behind login?
Micro-frontends (team independence) Bundle duplication, shared-state friction, design-system governance Do 3+ teams ship independently to the same surface?
Big design system investment Upfront months, governance overhead Are there β‰₯3 products/teams building UI?
Edge/global deployment Debugging complexity, data locality Is the audience global or regional?
Full type-safety end to end (OpenAPI/Zod codegen) Codegen pipeline setup, schema governance Do backend + frontend move fast enough that contract drift hurts? (Almost always yes)

1.4 The three-box mental model (before writing any code)

  1. Domain box: What is this system fundamentally? (A dashboard, a checkout, a collaboration tool…) β€” this decides state shape and data model.
  2. Delivery box: How does code reach users? (CDN, edge, regions, offline/PWA needs) β€” decides rendering and caching.
  3. Evolution box: What will change in 18 months? (New team members? Mobile app consuming the same API? Multi-tenancy?) β€” decides boundaries and contracts. Decide each box independently, then compose. Most bad architecture is mixing the three (e.g., choosing a data-fetching library because of a delivery concern).

1.5 The decision matrix (ask before every foundational call)

Score options 1–5 per row, weight the rows that matter to your context:

Criterion Weight (1–5) Option A Option B
Team familiarity & hiring
Reversal cost if wrong
Performance ceiling (your metrics)
Ecosystem maturity & longevity
Operational complexity (hosting, CI)
Fit with backend/org direction
Weighted total

Rule: if the matrix is within 10% and you have no data, pick the more boring option β€” boring scales in hiring, debugging, and longevity. Never pick an architecture to impress an interviewer; pick one that survives a team change.


Part 2 β€” The bootstrap blueprint (step-by-step)

Step 0 β€” Contract the problem (30–60 min, written)

Step 1 β€” Set up the monorepo (pnpm workspaces or Turborepo)

Step 2 β€” Next.js 15 App Router foundations

Step 3 β€” Define the data contract FIRST (contract-first)

Step 4 β€” Strict TypeScript, zero-exception

// packages/config/tsconfig.base.json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "verbatimModuleSyntax": true,
    "erasableSyntaxOnly": true,
    "moduleDetection": "force",
    "skipLibCheck": false
  }
}

Step 5 β€” Data layer (server state discipline)

Step 6 β€” Design system seed (don't boil the ocean)

Step 7 β€” Observability from day one (not week 12)

Step 8 β€” CI as the gate

Step 9 β€” Rollout & release discipline


Part 3 β€” AI-assisted architecture (make it a force multiplier)


βœ… The architecture checklist (before any foundational commit)

β†’ Next: 03 β€” Flawless Execution Β· Back: 01 β€” Visibility & Influence

← Visibility & Influence