Appearance
Tier 3 · Chapter 2: The Capstone
Synthesis & Capstone · project — plan for 15–25 hours
Why this capstone exists
Everything in this course has built toward making architectural decisions and defending them with honest trade-off reasoning. Reading about it and doing exercises gets you part of the way; the thing that actually cements architectural judgment is building the same real feature two different ways and living with the consequences of each. That's this capstone. You'll implement one product feature twice — two versions that differ along a single architectural decision — document the significant choices as ADRs, and write a trade-off review comparing the two builds. The point isn't to decide which version is "better" — by now you know that's the wrong question — it's to feel, in working code, what each option buys and costs, so the trade-offs stop being abstract.
There's a deliberate twist in how this capstone is set up, and it's the most important thing about it. Most engineers spend their careers inheriting architectural decisions rather than making them: you join a system that's already a monolith (or already split), already wired to a vendor (or not), already strongly consistent (or not), and you build features inside choices someone else made years ago. The decisions that define a system's shape are exactly the ones you rarely get hands-on reps with. So this capstone gives you a catalog of decision axes to choose from, and one selection rule:
Pick the axis you have the least hands-on exposure to. Stretch into the decision you've never actually made, not the one you make every sprint.
That's where the learning is. This mirrors the structure of Software Architecture: The Hard Parts, whose Sysops Squad saga is a worked, book-length version of taking a system and reasoning through a hard structural decision from both directions. You're doing a small version of that — building both sides of a decision you'd normally only ever inherit — and writing down what you learn.
The project
Build a support ticket feature — small enough to finish, rich enough to exercise the whole course. Pick your stack (the one whose Tier 2 track you did), and implement this scope:
Core feature: Customers create support tickets; the system assigns each to an expert; experts resolve tickets; resolving a ticket notifies the customer, schedules a satisfaction survey, and records an analytics event. Authenticated, authorized, validated, with the data consistency and async behavior the course has taught.
A real interface, not just an API. The feature is driven through a UI — at minimum a screen to list and resolve tickets — because the synthesis chapter's Dimension 2 (rendering and the client/server boundary) is a real architectural decision. If you did the Nuxt fullstack track, build the UI in Nuxt and treat your Nitro server routes as the backend-for-frontend. If you did the Laravel track, the frontend is a separate single-page app consuming the API, so your client/server boundary is a network-and-deployment seam. Either way, don't treat the UI as an afterthought.
You'll build this feature twice — but the two builds differ along one decision axis that you choose from the catalog below. Everything else (the feature, the stack, the deliverables) stays constant; the axis is the variable you're studying.
The decision catalog — choose your axis
Each axis below is a real architectural decision, framed as "build the same feature two ways." Each entry gives you the decision, the two builds (A and B) made concrete on the ticket feature, what the axis uniquely teaches, the course chapters it draws on, and how much exposure a typical engineer has to it. Choose the one axis you've had the least exposure to — and if two tempt you, note the second one; the trade-off review asks where it pulled at you.
Axis 1 — Build vs. buy (1st-party vs. 3rd-party)
- The decision: implement a capability yourself, or integrate a third-party service behind a boundary.
- Build A ↔ Build B: the resolve flow's side-effects (notify the customer, schedule the survey) built 1st-party — your own mailer, templates, delivery tracking — versus integrated from a 3rd-party SaaS (a transactional-email provider, a survey provider) wrapped in an anti-corruption layer so your domain never speaks the vendor's dialect.
- What it uniquely teaches: the anti-corruption layer / port-adapter boundary; resilience to a dependency you don't control (their outage is your outage → timeouts, retries, circuit breaker, and a fallback); lock-in, reversibility, and cost vs. control; testing against an external service (fakes, contract tests, sandbox); data ownership and privacy.
- Ties to: Foundations Ch1 (boundaries), Ch4 (reliability), Ch5 (communication); your track's API/integration chapter.
- Exposure: very low — engineers use SaaS constantly but rarely design the boundary and failure handling around it deliberately.
Axis 2 — Decomposition (modular monolith vs. service-split)
- The decision: keep the feature in one deployable, or split it into independently deployable services.
- Build A ↔ Build B: one application partitioned into enforced modules (
Ticketing,Notifications,Analytics) — in-process calls, one database, one transaction, a fitness function failing the build on a cross-module-internals import — versus a service-split where a ticketing service and a notification service each own their data and talk over the network. Build B confronts distributed transactions (no single-database atomicity), the reliability patterns on cross-service calls, and the fullstack twist: the UI now faces more than one backend, surfacing the BFF-vs-direct-calls decision (your Nitro layer aggregates the services, or the client orchestrates them). On the Laravel track that question lands on the separate SPA / an API gateway. - What it uniquely teaches: decomposition trade-offs, sagas and distributed transactions, network failure, independent deploy and operations.
- Ties to: Hard Parts (the whole book); Foundations Ch2 (styles), Ch3, Ch4, Ch5.
- Exposure: low — the monolith/split shape is almost always inherited, never chosen.
Axis 3 — Consistency (transactional vs. eventual)
- The decision: keep the resolve and its side-effects strongly consistent in one transaction, or let them become consistent eventually via events.
- Build A ↔ Build B: all the writes in one transaction, side-effects dispatched after commit but guaranteed — versus an event-driven flow where the resolve emits
TicketResolvedand the downstream effects happen eventually, with compensation and reconciliation when a step fails partway. - What it uniquely teaches: the real cost of "correct, eventually"; compensating actions and sagas; reconciliation; idempotency under redelivery; and how eventual consistency leaks into the UI — what does the user see in the window before things converge?
- Ties to: Foundations Ch3 (data & consistency), Ch5 (communication); Designing Data-Intensive Applications.
- Exposure: very low — most engineers reach for a transaction by reflex and never deliberately design an eventually-consistent flow.
Axis 4 — Sync vs. async control flow (orchestration vs. choreography)
- The decision: coordinate the resolve's multi-step reactions with one central coordinator, or let independent listeners react to events.
- Build A ↔ Build B: an orchestrator that runs notify → survey → analytics in sequence and owns the workflow's state and failure handling — versus choreography, where each reaction is an independent listener on
TicketResolvedwith no central coordinator. - What it uniquely teaches: where coordination logic lives; the trade between traceability/visibility (you can see the whole flow in one place) and decoupling/extensibility (you add a reaction without touching the others); and how failure handling differs (the orchestrator retries the workflow vs. each listener owning its own reliability).
- Ties to: Foundations Ch5; Hard Parts (workflow/saga); Building Microservices.
- Exposure: low-to-moderate — often present in a system but rarely chosen consciously.
Axis 5 — Deterministic vs. AI-augmented ⭐
- The decision: implement an "intelligent" step of the feature with deterministic rules, or with an LLM.
- Build A ↔ Build B: pick one smart step — auto-assign the ticket to the best expert, auto-triage its priority/category, or summarize the thread / draft a resolution. Build A does it with deterministic rules and heuristics (skill tags, round-robin, keyword priority); Build B does it with an LLM call that classifies, assigns, or summarizes.
- Why this is the capstone's capstone: it doesn't add an AI topic on the side — it synthesizes the entire course on the one subject nobody has architectural reps in yet. Building it forces every muscle at once:
- the model is a 3rd-party dependency you don't control → a latency/cost budget, timeouts, and a deterministic fallback path when it's slow, down, or wrong (this is Axis 1 + Foundations Ch4 in one);
- you can't unit-assert a probabilistic output → evals replace exact-match tests — a genuinely different testing model. A minimum-viable eval, so you're not starting from nothing: hand-label ~15–20 representative inputs with explicit acceptance criteria and require an N% pass threshold (say 90%), or have a second model grade each output against a rubric (LLM-as-judge); either way, track the score as a metric you watch move release to release, not a binary pass/fail gate. That's enough to tell whether Build B is actually working;
- the model's output is an untrusted boundary — constrain it to structured output and validate it with the same functional-rules discipline before your domain trusts it;
- sending customer ticket content to a model is a data trust-boundary and privacy decision, not a detail;
- nondeterminism leaks into UX and ops — guardrails, caching outputs, and observability of the model calls;
- the choice isn't binary — "use a model" is itself a spectrum of autonomy → once you're in Build B you still choose how much you hand the model: a single constrained, validated call (classify this ticket's priority) versus a chained multi-step workflow versus an autonomous agent that picks its own steps. The architectural move is the simplest point that works — for auto-assign, triage, or summarize that's almost always one constrained call, and reaching for an agent where a single call suffices is the premature-flexibility trap (Foundations Ch1) wearing AI clothing.
- The AI thread, inverted: everywhere else in this course AI is your thinking partner; here the AI is the subject of the architecture. Designing a system that depends on a probabilistic component is a rarer and more valuable skill than using one to write code. (Karpathy calls this layer "Software 3.0" — you program a probabilistic computer in English; the architectural question is which decisions you delegate to it and which you keep deterministic. The two ends of that question have names: Anthropic's Building Effective Agents argues for the simplest thing that works and constraining the model, while Boris Cherny's framing that for Claude Code "the product is the model" — the model and the product co-evolve in one loop — pulls the other way, toward leaning on the model itself rather than scaffolding around it — your two builds are a small experiment in where, for this feature, the truth sits between them.)
- Ties to: all of the above — Foundations Ch1, Ch3, Ch4, Ch5, and Axis 1. (Flagged: the course's six books predate LLM-application architecture, so this axis draws on current writing — cited in "Going deeper" — rather than the book set. Treat the specifics as current practice; the architectural reasoning is the course's.)
- Exposure: near-zero — almost no engineer has deliberately designed the boundary and failure model around a probabilistic dependency.
Axis 6 — Data store strategy (single store vs. polyglot)
- The decision: keep everything in one relational store, or move a concern into a specialized store.
- Build A ↔ Build B: all reads and writes in one relational database — versus polyglot persistence, where the primary data stays relational but a concern (ticket search, or the analytics/reporting read model) moves to a specialized store (a search index, a denormalized read store) kept in sync with the source of truth.
- What it uniquely teaches: when one store stops fitting; the real cost of a second store (the sync, the consistency window, the extra operational surface); read-model / CQRS-lite thinking; and the dual-write problem.
- Ties to: Designing Data-Intensive Applications (Kleppmann); Foundations Ch3; your track's persistence chapter.
- Exposure: very low — "just put it in Postgres" is usually never revisited.
What "two genuinely different builds" means
You don't need both builds to be production-grade or feature-complete — they need to be real enough that the difference along your axis is concrete and felt. A real transaction in one versus a saga with compensating actions in the other; an in-process call versus a network call with a timeout and retry; a deterministic rule versus a validated, fallback-guarded model call; one store versus two kept in sync. The learning is in the contrast, so build enough of each to feel the contrast honestly — and no more. A reviewer should be able to point at the two builds and see, in working code, exactly where your chosen decision changed the system.
What to document: ADRs
As you build, capture every significant decision as an ADR (the format from Foundations Chapter 1: title, status, context, decision, consequences — with the consequences section honestly naming costs). You're not documenting trivia; you're documenting the decisions where someone would later ask "why is it like this?" Aim for a handful of ADRs per build. Four want an ADR no matter which axis you chose:
- The boundary you drew — where the seam between the two approaches actually sits, and why (it connects to the consistency-unit / aggregate discussion in Foundations Chapter 3, shared by both tracks, and — on the Laravel track — its domain-modeling chapter).
- Your axis's central tension — the specific decision the axis is about (the per-axis ADR hints in the companion template name this for each one).
- The reliability measures — wherever your Build B introduced something that can fail in a way Build A couldn't (a network, a vendor, a model, a second store), name the timeouts, retries, idempotency, fallbacks, or reconciliation you added.
- The thing that surprised you — when you hit a place where one build was much harder than the other, that's an ADR documenting a real trade-off you discovered by building.
The ADRs are where the course's "name the trade-off, fit it to your context, write down why" discipline becomes a habit. Use the provided ADR + trade-off review template (the companion file in this folder) as your scaffold — it has per-axis ADR hints for whichever axis you picked.
What to write: the trade-off review
After both builds, write a trade-off review comparing them — the capstone's central deliverable, and the thing that proves you can do architectural reasoning, not just architectural construction. Use the synthesis chapter's dimensions (boundaries, rendering & the client/server boundary, transactions, async, testing, operations) as your lens, and for each one that's relevant to your axis, compare honestly what each build bought and cost in your actual experience building them. Not the textbook answer — what you actually felt. Where was Build A blessedly simple? Where did Build B's extra machinery genuinely help, and where was it pure overhead you'd never accept in a real project at this scale?
The review should end with a recommendation with reasoning: for a realistic version of this product — a real team, real scale, real constraints — which build would you actually ship, and why? This is the whole course in one judgment: not "which is better" but "which trade-off bundle fits this situation," defended honestly, with the costs of your choice named as clearly as the benefits. If your recommendation is "Build A, and I'd only move to Build B if [specific, evidence-backed pressure] appeared" — and you can say exactly what that pressure is and what you'd change first — you've internalized the central lesson of the entire course.
The AI thread
Throughout this course, the consistent move with AI is critique, not accept. The capstone is the strongest version of that exercise: use an AI coding agent to scaffold both builds quickly, then turn the architect's eye on what it produced — write the ADRs as a critique of the generated code (what boundary did it blur? what failure mode did it ignore? what cost did it hide?), not as a description of it. The scaffolding is cheap; the judgment about whether the scaffolding made the right trade-off is the thing this course certifies. (If you chose Axis 5, this gets reflexive — you're using AI to help build a system whose architecture is about depending on AI, which is exactly the kind of double-vision a modern architect needs.)
Two working habits make that critique-not-accept stance concrete, and both are just this course's own discipline pointed at the tool. First, separate planning from implementation: have the agent explore and propose a plan before it writes code, and treat that plan as the thing you review — an agent that jumps straight to code optimizes for looks done, and you'll inherit a solution to the wrong problem. Your ADR is that plan made durable; write it (or at least its skeleton) before you let the agent build, not after. Second, give the agent a runnable check — a test, a build that must pass, a linter, a script that diffs against expected output. Without a pass/fail signal it can run, "looks done" is the only signal available and you become the verification loop; with one, the loop closes on its own and you supervise outcomes instead of keystrokes. Both habits are deliberately tool-agnostic: the specific agent and its features change every few months, but "plan before you build" and "verify against something runnable" are the durable skills. (Flagged: these reflect current agentic-coding practice — e.g. Anthropic's Claude Code best-practices guide — not the course's book set; the underlying discipline is the course's own.)
How it's assessed
A reviewer evaluates the capstone on the reasoning, not the code polish. The questions they'll ask:
- Are the two builds genuinely different along your chosen axis — in the way that matters for that axis — so the contrast is real and visible in the code?
- Did you pick an axis you actually had to stretch for? The capstone is worth most when the decision was one you'd never made before.
- Do the ADRs name costs honestly? An ADR whose consequences section lists only benefits is hiding the trade-off, which is the one thing this course refuses to let you do.
- Does the trade-off review reflect lived experience, not textbook recitation? The valuable insights are the ones you could only have gotten by building both.
- Is the final recommendation defended by the situation, not by the appeal of an approach? "Service-split because microservices are modern," or "an LLM because AI is the future," fails; "the monolith because we're one team with no differential-scaling need, and here's the seam I'd extract first if that changed" passes.
There's no single correct answer — two thoughtful learners might ship different builds for the same product and both pass, if both defended the trade-off honestly for a coherent set of assumptions. That is the competency the course certifies: sound trade-off reasoning, costs named, decisions written down.
What a strong capstone demonstrates: the two builds are genuinely different along the chosen axis — you can point at working code and see where the decision changed the system — and every ADR's consequences section names real costs, not only benefits (an all-benefits ADR is the one thing the course refuses to allow). The deciding mark is the trade-off review: it reads as lived experience, not textbook recitation, and ends in a recommendation defended by the stated situation ("the monolith because we're one team with no differential-scaling need, and here's the seam I'd extract first if that changed") rather than by the appeal of an approach. If you can also say exactly what evidence would change your mind, you've turned the whole course into one honest judgment.
Suggested sequence
- Choose your axis from the catalog — the one you have the least exposure to. Then build the simpler / baseline version first (usually Build A: the in-house, the monolith, the transactional, the deterministic, the single-store). Get the feature working; it's your baseline. Write its ADRs as you go, not after.
- Build the second version — now you feel every cost of the alternative against the baseline the first gave you. Write its ADRs as you hit the decisions, especially the ones that were trivial in the first build and hard in the second.
- Write the trade-off review last — with both builds done and their ADRs in hand, the comparison and recommendation almost write themselves, because you've lived both sides.
Plan for 15–25 hours total. It's the capstone; it's meant to be substantial. The output — working code for both builds, a set of honest ADRs, and a trade-off review ending in a defended recommendation — is something you can show as evidence that you can do architecture, not just talk about it.
That's the capstone. Pick a decision you'd normally only inherit, build the feature both ways, document the choices honestly, compare them from lived experience, and defend a recommendation by the situation rather than the fashion. Do that, and the course has done its job — not because you can recite the patterns, but because you've made a real architectural decision and can defend it with the honesty the whole course has been training.
Going deeper (optional)
Software Architecture: The Hard Parts (Ford, Richards, Sadalage & Dehghani, O'Reilly, 2021) — the deep companion for Axis 2 and Axis 4; its decomposition and transactional-saga chapters, and the Sysops Squad saga, are a book-length version of building-and-comparing.
Building Microservices (Newman, 2nd ed., O'Reilly, 2021), "Splitting the Monolith" — directly on point for Axis 2's Build B.
Designing Data-Intensive Applications (Kleppmann, O'Reilly, 2017) — the deep companion for Axis 3 and Axis 6 (consistency, replication, derived/read stores).
Primary source: Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software (Addison-Wesley, 2003) — foundational for the "boundary you drew" ADR that every axis needs: aggregates as consistency units and bounded contexts as decomposition seams are the seminal version of where the seam between your two builds sits (relevant across Axes 2, 3, and 6).
Primary source: Gregor Hohpe & Bobby Woolf, Enterprise Integration Patterns (Addison-Wesley, 2003) — the canonical messaging-pattern catalog behind the eventual-consistency and choreography builds: Process Manager / saga coordination, idempotent receivers, and event-driven choreography (relevant to Axis 3 and Axis 4).
For Axis 5, the source books predate LLM architecture, so ground it in current writing — read for the trade-offs, not the hype:
- Andrej Karpathy, Software 2.0 (Medium, 2017) and Software Is Changing (Again) / "Software 3.0" (YC AI Startup School talk, 2025) — why a model is a fundamentally different kind of software component.
- Anthropic, Building Effective Agents (Dec 2024) — the single most useful read for this axis: when to use an LLM at all, "the simplest solution that works," the augmented LLM building block (a model with retrieval, tools, and memory), the workflow-vs-agent distinction (predefined code paths vs. the model directing itself), and the five composable patterns (prompt chaining, routing, parallelization, orchestrator-workers, evaluator-optimizer). This is the vocabulary behind the "spectrum of autonomy" point in Axis 5 above.
- Hamel Husain, Your AI Product Needs Evals (2024) — why evals, not exact-match tests, are how you verify a probabilistic component.
- Boris Cherny (Claude Code), "the model is the product and the product is the model" — his framing of Anthropic's own model/product loop; read it as a stance that leans on the model itself, a useful counterweight to the constrain-it school above (not a general prescription to skip scaffolding).
- Chip Huyen, AI Engineering: Building Applications with Foundation Models (O'Reilly, 2025) — the deep, book-length treatment of this axis as architecture: its final chapter walks the progressive build (guardrails → model router/gateway → caching → agent patterns → observability → user feedback), treating each as a design decision, and its evaluation chapters are the full version of the min-viable eval above. The strongest single follow-on if Axis 5 grabbed you.
- Suhas Pai, Designing Large Language Model Applications (O'Reilly, 2025) — companion to Huyen, heavier on RAG pipelines, agentic systems with guardrails/verifiers, and multi-LLM architectures (cascades, routers) — i.e. what the "polyglot of models" end of the spectrum looks like in practice.
(Flagged: current-ecosystem, not from the course's six-book set.)
Your own ADRs from the Tier 1 and Tier 2 deliverables — re-read them; the capstone is where that scattered practice becomes a coherent body of architectural reasoning.
Key takeaways
- The capstone is build one feature two ways along a decision axis you choose — to feel the trade-offs in working code rather than in the abstract.
- The selection rule is pick the axis you have the least exposure to — the decisions that shape a system are the ones engineers usually inherit instead of make, and this is your chance to actually make one.
- The catalog spans build-vs-buy, decomposition, consistency, sync-vs-async control flow, deterministic-vs-AI, and data-store strategy — and the AI axis is the one that synthesizes the whole course on the subject with the least prior exposure of all.
- Document decisions as ADRs with honest consequences; the central deliverable is a trade-off review comparing the builds from lived experience and ending in a recommendation defended by the situation, not the fashion.
- There's no single correct answer — the competency being demonstrated is sound trade-off reasoning with costs named honestly, which is the entire course in one judgment.
This completes the course. From trade-offs to styles to data, reliability, communication, and governance; through a full stack track; to one feature built two ways along a decision you chose and defended — you've practiced the whole arc of architectural thinking. The move never changes, at any scale, in any stack, on any decision: name the trade-off, fit it to your context, and write down why.