Chapter 4
How does web architecture shape scalability?#
- Created
- Updated
4.1 A conceptual model: separate roles from locations#
A framework-shaped label such as “serverless application” or “single-page application” combines several decisions that can be examined separately. Begin with four architectural roles:
| Role | Question it answers | Typical examples |
|---|---|---|
| Consumer | Who or what expresses intent and observes the result? | A person using a browser, an integration, a crawler, or an agent |
| Representation | What crosses a boundary to make state or action visible? | HTML, JSON, an image, a stream, a form, or a hypermedia control |
| Execution | Where is behavior evaluated? | A build process, browser, physical server, cloud service, or edge node |
| Authoritative state | Which component decides and preserves the current truth? | An application service, database, event log, or external system |
Roles are not machines.
One machine may perform several roles, and one role may be distributed across many machines.
An origin server serves the resource in an HTTP exchange, rather than forwarding the request as an intermediary; the role need not be one physical machine.
In web security and HTTP URI terminology, an origin is the normalized scheme, host, and port tuple, such as https, example.org, and 443 (RFC 9110, section 4.3.1).
CDN discussions also use “origin” as shorthand for the upstream origin server or backend; this placement alone does not identify the authoritative data store.
Likewise, an edge function may execute application logic without becoming the authority for the data it reads.
Use the Work Activity Tracker to keep the model concrete.
A GET /events request asks for a representation and may be answered from a browser cache, an edge cache, or the origin.
A lifecycle request, such as POST /work-items/item-42/transitions, asks to change an item's state.
Its success boundary must preserve the state change and matching activity event together; a derived summary may catch up later under a declared freshness policy.
The two paths can share an interface while placing execution, copies, and authority differently.
4.1.1 Trace a request across its commit boundary#
This illustrative start-work sequence separates the browser's knowledge from the authoritative result:
Browser API / application boundary Persistent store
| POST start(K) | |
|--------------------------->| authorize and validate |
| | begin transaction |
| |----------------------------->|
| | state + event + result for K |
| |<-----------------------------|
| | commit confirmed |
| success reply lost | |
| x--------------| |
| timeout: outcome unknown | |
The browser knows that it did not receive confirmation; it cannot infer that the mutation failed. A retry with the same logical-operation key can return the stored result when the receiver atomically preserves that key and effect. A new key can describe a new operation, and storing the receipt after the effect leaves a failure window. Name the owner of authorization, the transaction and the retry result before drawing a deployment diagram. The route and retry contract are examples; the project permits another interface with the same required behavior.
Pause & think
Separate response from outcome
An API commits an event to storage, then the network loses its response. The browser times out. Use only these stated facts to classify the outcome.
Automatically checked practice. Saved answers are private to your account.
Preview the exercise context for the assistant
This prepares an editable message. Review it in the assistant before sending. Your notebook notes are not included.
Checking saved answers…
Your answers to earlier versions
Show worked answer
The storage commit happened even though the browser received no confirmation. A timeout describes what the caller observed; it does not undo or disprove the commit.
For an optional executable check, open persisted-retry/README.md in the course workspace.
Its receiver and worker use separate records, so a process interruption can leave the effect committed while the worker's completion record is absent.
Explain what each record establishes and what remains unknown to the caller.
4.1.2 Automated consumers change demand and exposure#
A crawler, integration, monitoring probe, agent, and abusive bot may send similar requests while creating different value, cost, and risk.
Keep the operation's authoritative meaning stable across consumers, then decide which reads are public, which actions require authorization, and which expensive paths need quotas or admission control.
For the event tracker, a public summary might be cached while event writes require an authorized actor and a bounded request rate.
Cooperative crawling rules such as robots.txt do not enforce access control.
Appendix C develops crawler policy, rate-limit identity, and an endpoint review.
Sustainability angle
Placement determines resource flow. Chatty APIs, unnecessary round trips, duplicated computation, oversized payloads, heavy client bundles, aggressive polling, and poorly targeted edge execution all turn architectural choices into recurring resource use. Moving work is valuable when it removes a justified constraint rather than merely multiplying infrastructure.
4.2 Choose where work runs#
An origin-centered application can begin with one server handling requests and storing data. Separating presentation, application logic, and data into three tiers separates responsibilities; it does not require three machines. Cloud provisioning and programmable edges expand the placement options without removing the origin's authority or the need to recover from failure.
| Placement choice | Pressure it can address | Obligation to examine |
|---|---|---|
| Owned or hosted server | Predictable workload, hardware control, or data locality | Capacity planning, replacement, and recovery |
| Replaceable cloud instances | Variable demand and automated provisioning | Startup delay, quotas, shared state, and downstream saturation |
| Managed service | Limited team capacity for operating a database, queue, or storage layer | Provider limits, consistency, cost, export, and recovery contracts |
| CDN and programmable edge | Repeated delivery, distant consumers, or early request rejection | Cache correctness, execution limits, and distance to authoritative writes |
These choices can coexist in one application. The NIST cloud definition emphasizes pooled resources, rapid provisioning, elasticity, and measured service; these change how capacity is acquired, not how quickly a database can accept writes. A session, upload, or job kept only on one replaceable instance can disappear or become unreachable from the next request. Show where that state survives and which dependency saturates first.
A CDN moves reusable representations close to consumers; a programmable edge also runs bounded request handling there. The event tracker can deliver public assets and a cached summary near users while keeping event writes beside the authoritative database. If an edge function must contact that database on every request, the long trip remains. Choose placement from reuse, locality, trust, and operational capacity, and show managed dependencies and provider boundaries in the diagram.
4.2.1 HTTP provides a stable seam#
HTTP semantics define a stateless request-response protocol in which clients act on resources through messages and receive status information and representations in return. The protocol intentionally hides how a service is implemented behind a uniform interface. It also allows intermediaries—proxies, gateways, and tunnels—to participate between the user agent and origin. Those properties let deployment topology change without requiring every consumer to understand the new arrangement.
A request method communicates intent, the target identifies what the request concerns, headers carry metadata and control information, and the response status describes the result. Correct use of safe and idempotent methods, validators, cache metadata, authentication, and content negotiation affects what browsers and intermediaries are allowed to do. HTTP is therefore architectural material rather than plumbing supplied by a framework.
HTTP gives each request understandable semantics independently of its connection. Application identity, continuity, and durable state still need explicit owners; the data section develops those obligations.
4.2.2 Application contracts outlive deployment choices#
HTTP can carry several application interaction styles, including resource-oriented messages, hypermedia controls, GraphQL operations, and RPC calls. Each style distributes knowledge and change pressure differently between consumers and providers, but none removes the need to define representations, errors, retries, authorization, and compatibility.
For the project, choose one minimal event-creation and event-query contract, then ask how it changes when requests are retried, devices go offline, workflow states evolve, or consumers need additional data. Appendix C compares the interaction styles and contains annotated API exchanges and an executable HTTP example.
4.2.3 Organizational boundaries shape application contracts#
An application contract is also a communication contract between its owners. In his original 1968 paper, Melvin Conway observed that organizations tend to produce system structures shaped by their communication structures. For web architecture, this means that a shared API or data model can become the place where several teams must coordinate, while a nominally independent service can remain tightly coupled when every change still requires the same people to agree.
Do not create a service boundary merely to imitate an organizational chart. Instead, identify a capability with coherent authority and change reasons, give its owners enough control to evolve its internals, and keep the consumer contract small enough that other teams can depend on it without joining every implementation decision. When one workflow crosses several owners, record who may change the contract, how compatibility is checked, how consumers learn about deprecation or migration, and which decision requires cross-team agreement. The ownership card later in this chapter should therefore name both the code boundary and the communication boundary that maintains it.
4.3 Rendering moves work across time and place#
Cloud and edge platforms expanded where code can execute, while build tooling and capable browsers expanded when a representation can be created. Start with who constructs the next view and how it reaches the browser:
- A conventional multi-page application (MPA) follows links and submits forms to receive complete HTML documents.
- A hypermedia-driven application (HDA) keeps views and available actions in server-provided HTML; browser code follows those controls and can apply HTML fragments to parts of the page (Gross, 2022).
- A typical single-page application (SPA) fetches data and uses client-side rendering (CSR) to construct subsequent views without replacing the document.
These are representative flows, not mutually exclusive categories: a conventional MPA also uses hypermedia, and partial page updates alone do not distinguish HDA from SPA. The distinction in the latter two examples is whether server HTML or a client application model defines the views and actions. An HDA can still use scripts for local interface behavior (Gross, 2022).
Then ask how the initial view is produced. Server-side rendering (SSR) produces HTML for a request; static site generation (SSG) produces it ahead of requests; incremental static regeneration (ISR) refreshes previously generated HTML; CSR builds the view in the browser. CSR is the natural starting point for the SPA example, but an SPA can also initialize from server-rendered HTML and take over later rendering, as React's hydration API illustrates (React, n.d.). Caching server-generated HTML can serve an MPA or HDA without moving control of its views to the browser.
4.3.1 Web architecture lens#
Use the same event-recording interaction across three flows: a full HTML document, an HTML fragment and a JSON response interpreted by the client. Predict which component owns the view update and whether replacing the document preserves an unsent draft. Run the trace and inspect the artifact and ownership path; the draft-restoration choice is an explicit application policy.
Web architecture lens
What crosses the boundary after an action?
The first document may be rendered on the server, built ahead of time, or assembled in the browser. That is a separate choice from the later update below. All three examples start from the same loaded activity page.
Full-document navigation
- Response
- Replacement scope
Draft outside the activity list
A fragment or client render can also discard state if it replaces the draft's owner. In your project, inspect one real action in DevTools: method, status, content type, replaced DOM region and draft behavior. Make one bounded update with your model, then verify the saved event and draft separately.
4.3.2 Activation is a separate architectural decision#
4.3.3 Runtime generation adds a control boundary#
Runtime-generative UI lets model output choose data, composition, or executable behavior while the application runs. A descriptor needs a validated vocabulary of components and actions; executable output additionally needs isolation and tightly scoped access to host data and tools. Both need authorization at action time and a safe fallback. Appendix C develops these controls and the descriptor audit.
4.4 Data limits how freely responsibility can move#
Compute and representations can often be duplicated or replaced more easily than authoritative data. Identify the authoritative state for each domain outcome and the boundary that owns it. The book also uses state authority for this ownership question; it is separate from a caller's authorization to request a change. A read may be served from a replica or cache, but concurrent writes still need a rule for which result becomes true. Moving execution closer to users without deciding where authority lives can exchange network latency for inconsistent state, complex conflict resolution, or a longer path to the real owner.
For the event tracker, raw events, current work-item state, and derived summaries have different roles. Raw events may support replay or audit, current state must preserve workflow invariants, and summaries can often be rebuilt or temporarily stale. The architecture should state which data is authoritative, which is derived, where each is placed, and what happens when a location cannot reach its authority.
A derived summary may be rebuilt from retained events only when that history contains the necessary facts. Recomputing it must not repeat external effects such as notifications, and new events must not be lost during the rebuild. Appendix C works through a summary rebuild and cutover.
4.4.1 Data placement follows authority and access#
An origin-centered application can keep its primary database close to the application server and pay one predictable network cost for most operations. Cloud services make storage independently provisioned and managed, and they make replicas, object stores, queues, and analytical systems easier to combine. Edge execution makes the remaining distance more visible: code may run near a consumer while the authoritative write still has to cross a region or continent.
Choose a data shape from the behavior that must remain correct and the access path that must remain efficient. A relational model is useful when constraints and relationships must be enforced together; a document can keep an aggregate together; a key-value store can serve known-key access; object storage can hold large immutable representations; and an append-oriented log can preserve history for replay or derivation. These are composable roles rather than stages of progress. One application may use a relational source of truth, object storage for attachments, and a derived search index without giving all three equal authority.
4.4.2 Stateless requests still depend on state#
An interchangeable server may receive a workspace handle without sharing an earlier request's in-process session. It must still authenticate the caller, authorize access, and resolve authoritative state. A handle does not grant permission, and state available only on its originating instance still requires affinity. Retries after a lost response need a stable application command identity, with the mutation and reusable result stored atomically. Appendix C provides the two-instance state and retry audit.
4.4.3 Transactions preserve invariants across failure and concurrency#
A transaction groups operations that must commit together and defines how concurrent work may interact. For the event tracker, a successful lifecycle transition must update current state and append its activity event without allowing either write to escape alone. The deployed database's constraints, isolation level, acknowledgment point, and failure model determine the actual guarantee.
Appendix C develops ACID, concurrent transitions, and the transaction lab.
4.4.4 Model valid data combinations#
Constructive data modeling uses tagged unions, sealed hierarchies, or guarded constructors to require the data belonging to each outcome. It reduces contradictory in-memory values; runtime parsing, authorization, and atomic persistence still enforce their own rules. Appendix C develops a transition-result example and selected-invariant exercise.
4.5 Caching coordinates controlled copies#
Caching began as a central content-delivery technique, but its architectural reach is wider than the CDN. A browser can keep a private response, a shared intermediary can reuse an HTTP representation, an application can retain a computed result, and a data system can expose a replica or materialized view. Each case creates a controlled copy whose identity, lifetime, and relationship to authority must be defined.
| Cache location | Copy being reused | Main benefit | Main correctness question |
|---|---|---|---|
| Browser | A response for one user agent | Avoids transfer and repeated work | May this user reuse it, and when must it validate? |
| CDN or reverse proxy | A response shared across suitable requests | Reduces latency and origin work | Which request properties belong in the cache key? |
| Application | A query, computation, or assembled view | Avoids repeated service or data work | What invalidates it, and can callers accept bounded staleness? |
| Data layer | A read replica, index, or materialized result | Moves or accelerates read work | How far may it lag behind the authoritative write path? |
4.5.1 HTTP cache control is application policy#
An HTTP cache can avoid an origin request, reduce transferred bytes, and hide network latency only when reuse is correct for the response and its consumers. The response must communicate who may store it, how long it remains fresh, how it can be validated, and whether stale reuse is acceptable.
The HTTP caching specification defines the core directives and freshness model:
publicpermits storage by shared caches, whileprivatelimits a response to private caches.max-agedefines freshness relative to response generation;s-maxagecan define a different freshness lifetime for shared caches.no-cachestill permits storage, but the stored response has to be validated before reuse.no-storeasks caches not to store the response at all.must-revalidateprevents reuse of a stale response without successful validation.Varymakes selected request headers part of response selection. This can protect correctness, but every varying dimension can fragment the cache.
The cache key must distinguish requests whose responses or required processing differ.
Query parameters can fragment reuse even when they only describe a campaign, but ignoring an authorization or content-selection parameter can make reuse incorrect.
Appendix C develops the optional No-Vary-Search mechanism and its limits.
Validators avoid retransmitting an unchanged body.
An origin can attach an ETag; once the stored response needs validation, a cache sends that value through If-None-Match.
A matching validator allows the origin to return 304 Not Modified without the representation body, while a changed validator produces a new 200 response.
The stale-while-revalidate extension moves latency again: a cache may immediately serve a stale response for a bounded period while validating it in the background.
That can be appropriate for a public activity summary, but not for every response.
Personalization, authorization, invalidation, and the cache key are correctness and security decisions rather than deployment details.
4.5.2 Cache decision lab#
The lab below follows a second request through browser cache, shared cache, and origin. Change the response profile, move time forward, and decide whether the origin representation changed. Then inspect whether the request is served fresh, served stale while validation happens, conditionally revalidated, or fetched in full.
HTTP cache lab
Where does the next response come from?
Every case begins after one successful response. Change its policy and age,
then trace the next request without changing the URL. For an executed
browser observation, try the optional
local practice workspace
and choose http-cache/README.md.
4.5.3 Local practice: HTTP caching#
For optional local practice, open http-cache/README.md in the course workspace.
It supplies a local origin and browser page, leaving one conditional-response function to implement with your model.
Predict body versions and origin-request counts, then inspect actual browser reuse and network 200/304 records.
It focuses on private browser caching; shared caches and CDN behavior remain separate investigations.
Maintain its specification and one decision record within existing practice time, with no additional submission or grading criterion.
Cache behavior should be tested at the deployed boundary because application code is only one participant.
A framework, reverse proxy, CDN, browser, or hosting platform may add, remove, or reinterpret cache metadata.
Record the final response headers, cache status, Age, and origin traffic rather than assuming the source-code declaration is the complete policy.
4.6 Architecture is maintained as responsibility moves#
Throwaway code, piecemeal growth, and pressure to keep a system working can gradually blur its structure (Foote & Yoder, 1997). Adding services, edge functions, browser state, or caches creates more responsibilities to keep coherent. Record their owners, revisit temporary shortcuts, and reorganize code when several unrelated change reasons accumulate together. Architecture notes and a decision log preserve those choices for later contributors.
4.6.1 Field note — When syntax familiarity stopped deciding the stack#
Agents let me explore technologies before I know every syntax detail or API. I am using that capability in an Apache Jena proof of concept for validating a knowledge base. I am not a strong Java developer, and I do not yet know whether this is the right architecture; the immediate question is whether the approach produces useful results.
I can delegate unfamiliar syntax while examining the data model and observed behavior. If the prototype proves useful, its architecture, maintainability, and my ability to own it still need review.
4.6.2 Make the implementation architecture reviewable#
By this point, you have already made architecture choices in implementation A, even if you did not yet have a complete vocabulary for them. The public project discussion should make those choices visible: different groups received the same behavioral specification but chose different stacks, boundaries, storage models, and request paths.
Keep the architecture diagram consistent with the project harness: global rules, feature contracts, decision records, and agent instructions should describe the same implementation.
A component diagram can show that two boxes exist without explaining which one owns a decision. For each independently evolvable capability, record its source root, composition root, authoritative state and its owner, public contracts, allowed dependency direction, and intentionally excluded responsibilities. The resulting ownership card is a review aid rather than a demand for one directory per feature.
File size, fan-in, churn concentration, or a crowded directory can act as structural smoke alarms, but none proves that a split is correct. When such a signal fires, inspect whether several authorities or change reasons have accumulated together. Consolidate ownership, split responsibilities, or document a justified exception; do not divide a file merely to satisfy a number.
State which failure or future change the proposed repair should improve, then check its consequences. The architectural-degradation review maps measurement and remediation techniques, while distinguishing their reported frequency from evidence of effectiveness (Ahmad et al., 2026). Record the repair's cost, later change and review effort, regressions, and whether the original problem returns. A lower structural metric alone cannot establish that the repair was worthwhile. Appendix A's optional repair comparison applies this reasoning to successive changes in the same implementation.
4.7 Architectural dimensions for a web application#
Placement, rendering, data, and ownership choices interact along several dimensions. Use the table to compare architectures without treating any option as a universal destination.
| Dimension | Available choices | Pressure the choices can address | Obligation introduced by the decision |
|---|---|---|---|
| Infrastructure ownership | Owned server, hosted machine, VM, container, function, managed service | Provisioning speed, utilization, operational capacity | Provider contracts, quotas, cost visibility, and recovery |
| Execution placement | Build system, browser, origin, cloud region, edge location | Latency, elasticity, device capability, or data locality | More boundaries, deployment targets, and partial-failure paths |
| Representation rendering | Build time, request time, incremental regeneration, client time | Freshness, origin work, delivery speed, personalization | Invalidation, duplicated logic, activation, and fallback behavior |
| Browser interaction | Document navigation, hypermedia updates, client-managed navigation | Interaction richness, continuity, client responsiveness | Client state, compatibility, accessibility, and recovery |
| Client activation | Hydration, progressive hydration, islands, resumability | Initial payload and time to useful interaction | Serialization, loading policy, tooling, and cross-boundary state |
| Authoritative state owner | Client-local state, application service, database, event log, external owner | Correctness, offline work, audit, and integration | Invariants, authorization, retries, and lifecycle |
| Data distribution | Central store, replicas, partitions, derived views | Volume, locality, isolation, and read or write pressure | Consistency rules, routing, migration, and reconciliation |
| Caching and freshness | Browser, intermediary, application, and data-layer copies | Repeated work, transfer, latency, and origin capacity | Cache identity, freshness, invalidation, privacy, and observability |
| Consumer contract | HTML and forms, resource HTTP, hypermedia, GraphQL, RPC, events | Independent evolution and different consumer needs | Compatibility, idempotency, rate limits, and bounded authority |
| Operational ownership | One team and machine through multiple teams, providers, and regions | Organizational scale and specialized capability | Explicit ownership, signals, incident paths, and decision records |
The rows interact. Moving rendering to the edge may require a cache-freshness policy; moving interaction to the browser may require a new API contract; moving compute into replaceable cloud instances may require state to leave process memory; and moving reads near users may lengthen the path to authoritative writes. Check that the consequences of those choices agree.
4.8 Project artifact#
Review the architecture and data-flow diagrams submitted with implementation A, identify one consequential architectural choice, and write an architecture hypothesis for implementation B. The hypothesis should use the conceptual model and dimensions table to state:
- which consumer, representation, execution location, and authority the selected workflow uses,
- which pressure justifies preserving or changing that placement,
- what new contract, consistency rule, or operational obligation follows,
- which automated consumers may reach the selected path and where cooperation, access control, quotas, or rate limits belong,
- which team or organizational boundary owns the contract and which changes require coordination across it,
- and what evidence would show whether the decision works.
Also complete an ownership card for the event workflow and identify one structural signal that would prompt another ownership review. Implementation B should still include its own diagrams and decision record.
4.9 Summary#
4.10 References#
- Foote, B., & Yoder, J. W. (1997). Big Ball of Mud. Proceedings of the Fourth Conference on Pattern Languages of Programs. https://www.laputan.org/mud/
- Gross, C. (2022, February). Hypermedia-Driven Applications. htmx. https://htmx.org/essays/hypermedia-driven-applications/
- Gross, C. (2022, November). Hypermedia-Friendly Scripting. htmx. https://htmx.org/essays/hypermedia-friendly-scripting/
- React. (n.d.). hydrateRoot. React documentation. Retrieved https://react.dev/reference/react-dom/client/hydrateRoot
- Ahmad, N., Su, R., Esposito, M., Janes, A., Lenarduzzi, V., & Taibi, D. (2026). Architectural Degradation: How to Measure and to Remediate. arXiv Preprint arXiv:2610.01611. https://arxiv.org/abs/2610.01611