Architecture

Once by the book.
Once across a whole system.

Move from a diagram to the consequences of a decision. See where responsibilities live in a UI and on a server, how the two talk, how the system fails, and how you would know a change was worth making.

Moving in. 48 of 48 topics have lessons; they're moving over from the old site.

48 topics

Moving in 48 of 48 topics have lessons, which are moving over from the old site. Planned topics show where the catalog is going.

Client and server

The model every web application starts from, and the choices about how much the client knows.

Architecture moving

Client–server architecture

The browser asks and the server decides: where truth lives, what to trust, and the network in between

TypeScriptGo
Architecture moving

Backend for frontend

Give one UI a server layer that reshapes the APIs behind it

TypeScriptGo
Choice moving

REST, RPC, or GraphQL

Choose the shape of the contract between client and server

TypeScriptGo
Choice moving

Polling, server-sent events, or WebSockets

Keep a screen current while the server’s data changes

TypeScriptGo
Architecture moving

Local-first and sync

Let the client own a replica that works offline and reconciles with the server

TypeScriptGo

Failure and evidence

Expect each part to fail in specific ways, decide what success means, and measure before and after a change.

Technique moving

Thinking in failure modes

For each dependency, ask what happens when it is slow, down, wrong, duplicated, or half-done

TypeScriptGo
Architecture moving

Containing failure

Keep one failing dependency from taking the rest down: timeouts, circuit breakers, bulkheads, and degraded modes

TypeScriptGo
Technique moving

Defining success

Decide what working means before you change anything: SLIs, SLOs, and error budgets

TypeScriptGo
Architecture moving

Observability across a request

Follow one request through logs, metrics, and traces across every service it touches

TypeScriptGo
Technique moving

Baseline before you change

Measure before and after a refactor, so you know whether it was worth doing

TypeScriptGo
Technique moving

Fitness functions

Turn an architecture’s promises into checks that run on every change

TypeScriptGo

Decompose a system

Find the lines a system should split along, and recognize when a line is in the wrong place.

Architecture moving

Decomposing a system

Split by what changes together and hide what is likely to change, rather than by technical layer

TypeScriptGo
Architecture moving

Bounded contexts

Let a word like “customer” mean different things to billing and support, on purpose

TypeScriptGo
Architecture moving

Who writes this data?

Find boundaries by asking which part of the system is allowed to change each record

TypeScriptGo
Architecture moving

Conway’s law and team boundaries

Systems end up shaped like the teams that build them, so draw both on purpose

TypeScriptGo
Architecture moving

Signs a boundary is wrong

Every change touches two modules, calls between them are chatty, and services must deploy together

TypeScriptGo
Choice moving

How big should a module or service be?

Weigh fine-grained pieces against coarse ones by change, ownership, and the cost of every call between them

TypeScriptGo

Organize an application

Where responsibilities live inside one application, on a server or in a UI, and which parts may know about which.

Architecture moving

Layered architecture

Split routes, services, and data access into layers, and notice when the service layer becomes a junk drawer

TypeScriptGo
Architecture moving

Hexagonal / ports & adapters

Keep application behavior independent of the frameworks, databases, and APIs around it

TypeScriptGo
Architecture moving

Vertical slices

Group code by feature, so one change stays in one folder

TypeScriptGo
Architecture moving

Plugin architecture

Keep a small core that others extend, like Vite plugins or editor extensions

TypeScriptGo
Architecture moving

Pipes and filters

Pass data through independent steps, like a build transform chain or a Unix pipe

TypeScriptGo

Frontend applications

How a UI splits state, data, and rendering, and who owns each.

Architecture moving

State ownership in a component tree

Decide which component owns each piece of state, and how it reaches the ones that read it

TypeScriptGo
Architecture moving

Unidirectional data flow

Send every change through one path: action, store, render

TypeScriptGo
Architecture moving

Server state in the client

Treat fetched data as a cache the server owns, with its own staleness rules

TypeScriptGo
Choice moving

Server, static, or client rendering

Choose where and when each route’s HTML is produced

TypeScriptGo
Architecture moving

Micro-frontends

Split one product UI across teams and deployments, and see what the browser pays for it

TypeScriptGo

From modular monolith to services

Build one deployment so a module could become a service later, and know when that move has earned its cost.

Architecture moving

Modular monolith

One deployment built from modules with an owner, a public API, and boundaries something enforces

TypeScriptGo
Architecture moving

Module contracts

Expose operations and plain data, never internals, so a module’s API could survive becoming a network call

TypeScriptGo
Architecture moving

Communication between modules

Choose direct calls or in-process events, and write each one as if it could fail or arrive late

TypeScriptGo
Architecture moving

Module-owned data in one database

Give each module its own tables and no joins across them, while still sharing one database

TypeScriptGo
Architecture moving

Consistency without a shared transaction

Plan for the day two modules can no longer commit together

TypeScriptGo
Architecture moving

Extracting a service

Find the seam, run old and new side by side, hand over the data, and keep a way back

TypeScriptGo
Choice moving

Modular monolith vs. services

Decide when one deployment is enough and when a capability has earned its own service

TypeScriptGo

Events, queues, and workflows

Work that happens later, elsewhere, or across several systems.

Architecture moving

Event-driven architecture

Let parts of a system react to things that have already happened

TypeScriptGo
Architecture moving

Work queues and background jobs

Move slow work out of the request and run it reliably later

TypeScriptGo
Architecture moving

Receiving webhooks

Accept events from another company’s system: verify, deduplicate, and respond quickly

TypeScriptGo
Architecture moving

Transactional outbox

Save a change and the message announcing it in the same transaction

TypeScriptGo
Architecture moving

Sagas and compensation

Run a multi-step workflow across services, and undo completed steps when a later one fails

TypeScriptGo

Data

How a backend records change, answers questions, and keeps customers apart.

Architecture moving

CQRS

Give reads and writes different models where their needs diverge

TypeScriptGo
Architecture moving

Event sourcing

Store changes as events, then build the views that read them

TypeScriptGo
Architecture moving

Change data capture

Stream a database’s committed changes to search indexes, caches, and other systems

TypeScriptGo
Choice moving

Multi-tenant data isolation

Separate customers by row, schema, or database

TypeScriptGo

Deploy and evolve

Choose where the code runs, and move a live system to a new shape without stopping it.

Architecture moving

Strangler fig migration

Replace an old system one route at a time while both keep running

TypeScriptGo
Choice moving

Long-running servers vs. functions

Choose between a process that stays up and code that runs per request

TypeScriptGo
Architecture moving

Expand and contract

Change a database schema or API without breaking the version still running

TypeScriptGo
Architecture moving

Branch by abstraction

Swap out a dependency behind a seam while still shipping from main

TypeScriptGo