Chapter 15 · Week 15

Architecting the Whole System

What does it mean to build well, not just big?

Chapter 15 — Architecting the Whole System

“The architect’s most important single gift is the integrity of the design — the assurance that it is one mind’s product, that the whole hangs together.” — Fred Brooks, The Mythical Man-Month

“According to the grace of God given to me, like a skilled master builder I laid a foundation, and someone else is building upon it. Let each one take care how he builds upon it.” — 1 Corinthians 3:10


Why This Matters

Fourteen weeks ago you could not say what a list costs. You measured it into your hands. You built the dynamic array, the linked list, the hash map, the tree, the graph. You watched a linked list lose a footrace to an array because of cache lines, and you learned the lesson that runs through this whole book: asymptotics can lie at real scale, and the architect is the one who knows when.

Then you went outward. A server is a program that waits at a port. You built one in Node and the same one in FastAPI, and the choice between them stopped being an accident of what you learned first and became a decision you have felt from both sides. You persisted data in SQLite, in Postgres, in Mongo, and each time you were forced not just to make it work but to justify the tool. Last week you put a face on the system — a front end that is good enough, no more.

This week, all of it comes together into a single act: architecting a whole system from its constraints.

This is the intellectual climax of the book. Not because there is a hard new algorithm — there isn’t. The new thing is harder than an algorithm. It is judgment. The whole course was a long, expensive education in the cost of every choice, precisely so that this week you can do the one thing no machine can do for you: look at a real problem, name its constraints, and let the right architecture fall out of them.

Here is the thesis of the entire book, stated as sharply as I can state it:

AI builds what you specify. The architect decides what’s worth building — and what it will cost.

An agent can build a well-specified module faster than you can. It can scaffold a project, write the boilerplate, generate the migrations, draft the tests. What it cannot do — what it has no way to do — is decide which system to build in the first place, under your constraints, for your users, on your budget. That decision is the architect’s, and it is the one we train this week.

The Christian question for the week is the oldest building question there is: what does it mean to build well, not just big? Scripture frames it as a contrast. At Babel (Genesis 11), humanity builds a tower “with its top in the heavens” to “make a name for ourselves” — building big, building for self, and it ends in confusion and scattering. At the end of the story, the New Jerusalem “comes down out of heaven from God” (Revelation 21) — a city whose builder and maker is God, measured, ordered, with foundations and gates and a wall whose dimensions are given. One is built big for the builder’s glory and collapses into noise. The other is built well, to a measure, for those who will live in it. The architect’s whole vocation lives in that contrast. Paul makes it personal in 1 Corinthians 3:10: let each one take care how he builds. Care is the word. This chapter is about care.

There is no new project this week. Project 14 — the capstone — is next week, and it is open-AI, take-home, with a 60-minute live integration session. This week’s work is to learn the architect’s method explicitly, walk through it on real problems, and then prepare for the final by writing the one document that the final grades most of all: the architecture document, written first.


15.1 — The Architect’s Method: Start From Constraints, Not Technology

Here is the single most common mistake junior engineers make, and the single most common mistake a vibe-coder makes with an AI:

They start from the technology. “Let’s build it in React with a Postgres backend and a microservices architecture.” Then they go looking for a problem that fits the tools.

The architect runs the arrow the other direction. The problem comes first. The constraints come second. The technology falls out last — as a consequence, not a premise.

You already believe this for data structures, because Phase 1 beat it into you. You don’t reach for a hash map because hash maps are cool. You reach for a hash map because the problem is membership-or-lookup with no ordering need, and a hash map is what that constraint deserves. If the problem needed ordered iteration or range queries, you’d reach for a tree instead — same skill, different constraint, different answer. The structure falls out of the constraint.

Architecting a whole system is the exact same move, one level up. Instead of choosing a structure, you’re choosing a stack: a server, a database, a front end, and the seams between them. But the method is identical. Name the constraints. Let the tools fall out.

The seven constraint questions

Before you write one line — before you prompt one agent — you answer these. In writing. Every time.

  1. Who are the users, and how many? Five people in one church office? A thousand congregants on their phones? The public internet? The user count and the user kind drive nearly everything downstream.
  2. What is the read/write shape? Is this read-heavy (a verse-of-the-day everyone views) or write-heavy (everyone submitting at once)? Bursty or steady? This is the same read/write analysis you did when choosing between structures in Phase 1 — now applied to a database.
  3. What must be consistent? If two people sign up for the last spot in a small group at the same instant, can you tolerate both succeeding? For money, attendance caps, or seats: no. For a view counter: probably yes. Consistency requirements are where the hardest architecture lives, and they are the part an agent will silently get wrong.
  4. What is the budget? Dollars per month, yes — but also the complexity budget. Every moving part is a part that can break at 2 a.m. A volunteer-run church tool has a near-zero ops budget. That constraint alone rules out half the “best practices” the internet will recommend.
  5. What is the team? One person who knows Python? A volunteer who knows a little JavaScript? You build with the tools the team can maintain, not the tools that are theoretically optimal. The best architecture your team can’t keep running is worse than the second-best one they can.
  6. What is the timeline? This weekend? This quarter? Timeline decides how much you build versus buy versus cut. It is the single biggest input to MVP scope (§15.4).
  7. What changes next? What is likely to grow, and what is likely to stay small forever? You architect for the change you can see coming — not for every change you can imagine. Over-architecting for imaginary scale is its own Babel.

Notice what is not on this list: “what’s the coolest tool,” “what does my favorite YouTuber use,” “what looks good on a résumé.” Those are not constraints. They are temptations.

Coach’s Note — Write the seven answers down before you choose anything. Not in your head — on the page. The discipline of writing them is what stops you from quietly skipping the one you don’t want to think about (it’s almost always #3, consistency). The page is honest in a way your head is not. This is the same lesson as “spec before you build” from Coding 2, scaled up to the whole system.


15.2 — The Master Decision Framework: From Constraints to Stack

Once the seven answers are on the page, the stack falls out in four sub-decisions. Here is the whole course, compressed into one decision procedure. Read it top to bottom; it is the order you actually decide in.

Decision 1 — Structure choice (the Phase 1 cost intuition)

This one happens inside every other decision, so it comes first. For each piece of data your system holds in memory and operates on, ask the Phase 1 question: what does this access pattern cost?

If the access pattern is…Reach for…Because (the cost)
Index by position, append-heavydynamic array / listO(1) amortized append, O(1) index, cache-friendly
Membership / lookup by key, no orderhash map / dictO(1) average lookup; no ordering guarantee
Ordered iteration, range queriestree / sorted structureO(log n) ordered ops; this is what a DB index is
Relationships, paths, dependenciesgraphmodel the connections explicitly; choose list vs matrix by density
FIFO work hand-off between workersqueuethe producer/consumer shape from the midterm

This is not abstract. A database index is a tree or a hash chosen for you (Week 12). When you add an index in Postgres, you are making the Phase 1 tree-vs-hash decision at the storage layer. The cost intuition you built by hand is exactly the intuition that tells you which index to add and which to skip.

Decision 2 — Server choice (Node vs FastAPI)

Constraint points to…ChooseWhy
Team knows JavaScript; many concurrent I/O-bound connectionsNode.jssingle-threaded event loop is excellent at many idle/I-O-bound connections (Week 9’s Hard tier)
Heavy request/response validation; data shapes matterFastAPIPydantic models are specifications; validation is free and automatic (Week 10)
Must integrate with Python (ML model, data libraries, pandas)FastAPIyou’re already in Python; don’t cross a language boundary for nothing
CPU-bound work per requestneither alonethe GIL (Python) and the single thread (Node) both choke on CPU-bound work; reach for processes/workers
Genuinely either would dothe one your team maintainsa tie breaks toward maintainability, every time

Remember the honest truth from Weeks 9–10: for a small JSON API, both are fine. The decision is rarely about raw capability at small scale. It’s about team, validation needs, and what else the system must talk to.

Decision 3 — Database choice (SQLite vs Postgres vs Mongo)

This is the decision the whole persistence arc (Weeks 11–13) was built to teach. The constraint that decides it is almost always write concurrency and data shape.

ConstraintSQLitePostgreSQLMongoDB
Concurrent writersone at a time (file lock)many (MVCC)many
Setup / ops cost~zero (one file)real (a running server)real (a running server)
Data shaperelationalrelationaldocument / nested
Strong consistency, transactions, joinsyesyes, best-in-classweaker; possible but not the strength
Schema flexibility (varying fields)rigidrigid (mostly)flexible
Right when…MVP, single writer, read-heavy, low ops budgetreal concurrent writes, relational integrity, growthgenuinely document-shaped data, varying structure

The single sentence that decides most cases: “a single file, one writer at a time” (SQLite) is the right MVP tool until concurrent writes or multi-machine access force you off it — and only then do you reach for Postgres. Reaching for Postgres when SQLite would do is its own architectural mistake (Week 12’s whole point). And you reach for Mongo only when the data is genuinely document-shaped (varying fields, deep nesting) — not because relational schemas feel like work (Week 13’s whole point).

Decision 4 — Front end (the MVP “good enough”)

You learned this last week. For the systems this course builds, the front-end decision is usually:

Plain HTML/CSS/JS talking to your API with fetch() is good enough for the MVP. A framework (React, Vue, Svelte) earns its keep only when the UI’s state complexity grows past what hand-written DOM updates can keep straight — many interacting components, lots of client-side state, a team that already knows the framework.

If you can’t name the specific state-complexity problem a framework solves for this app, you don’t need the framework yet. That’s not Luddism; it’s cost-counting.

Coach’s Note — Read the four decisions again and notice: not one of them is decided by the technology being good or bad. Postgres is not “better than” SQLite. Node is not “better than” FastAPI. React is not “better than” plain JS. Each is the right tool under some constraint and the wrong tool under another. The day you stop asking “which is best?” and start asking “which does this constraint deserve?” is the day you become an architect. There is no universally best tool. There is only the right tool for the job.


15.3 — A Fully Worked Example: The Small-Group Sign-Up Tool

Enough framework. Let’s architect a real thing, out loud, naming every constraint and every tradeoff. This is exactly the move Project 14’s architecture document asks for.

The problem (from a real church): “We have a 1,200-member congregation. Twice a year we launch about 40 small groups, each with a cap of 8–12 people. Members need to browse the groups, sign up, and see which ones are full. Leaders need to see their roster. Right now it’s a paper sign-up sheet in the lobby and a volunteer typing it into a spreadsheet, and every season two people end up double-booked and one group is over capacity.”

Step 1 — Answer the seven constraint questions

  1. Users, how many? 1,200 members total, but the concurrent count matters more. Sign-ups open after a Sunday service. Realistically a few hundred people might open the page within the same hour, with maybe a few dozen actually submitting in the same few minutes. Plus ~40 leaders checking rosters. Public-ish (anyone with the link), but low total scale.
  2. Read/write shape? Overwhelmingly read-heavy — most people browse groups before signing up, many never sign up at all. Writes are rare per user (you sign up once or twice a season) but bursty: a spike right after the announcement.
  3. What must be consistent? This is the heart of the problem. A group has a hard capacity. If two people grab the last seat in the same instant, the system must not let both in. Capacity enforcement requires real consistency on writes. This is the constraint the paper sheet fails at, and it’s the reason the tool exists at all.
  4. Budget? Volunteer-run church. Near-zero dollars, and — more importantly — near-zero ops budget. Nobody is going to babysit a server cluster. Whatever this is, it has to keep running with essentially no maintenance.
  5. Team? One person — you — plus maybe a volunteer who knows a little Python. So: Python-friendly, and simple enough that one person can maintain it.
  6. Timeline? Needs to work for the next sign-up season, ~6 weeks out. One person, part-time.
  7. What changes next? Group count and member count are stable (a congregation doesn’t double overnight). The thing most likely to change is features — leaders wanting email exports, a waitlist, attendance tracking. So architect for feature growth, not scale growth.

Step 2 — Let the stack fall out

Server: The team knows Python. There’s meaningful validation (group caps, valid member info, no duplicate sign-ups). FastAPI’s Pydantic models give that validation almost for free, and the auto-docs help a solo maintainer. Choose FastAPI. Could Node do it? Yes. But the team is Python-leaning and there’s no JavaScript-specific reason to cross over. The constraint (team + validation) points to FastAPI.

Database: Here is where the consistency constraint (#3) does the heavy lifting. Capacity enforcement is a write-concurrency problem: two simultaneous sign-ups for the last seat. SQLite’s “one writer at a time” file lock is actually an asset here at this scale — serialized writes mean the last-seat race resolves cleanly, one writer at a time, and the burst is small enough (dozens of writes in a few minutes) that the single-writer bottleneck never bites. The data is cleanly relational (members, groups, sign-ups with a join table). The ops budget is near zero, and SQLite is a single file with no server to babysit.

Choose SQLite. Enforce capacity with a transaction: inside one transaction, count current sign-ups for the group, and insert only if under cap — BEGIN; SELECT count(*); INSERT IF under cap; COMMIT; — so the check-and-insert is atomic. Add a uniqueness constraint on (member_id, group_id) so the same person can’t double-book (the 409-Conflict lesson from Week 11). This is the part the paper sheet could never do, and it’s the part you must design — an agent will happily write a sign-up endpoint that checks the cap outside a transaction and ships the exact race condition the tool exists to prevent.

Front end: A few pages — a group list, a sign-up form, a leader’s roster view. State complexity is low. Plain HTML/CSS/JS with fetch() is good enough. A framework would be ceremony with no payoff here. This is “minimum lovable,” not “gold-plated” (§15.4).

Structures (Phase 1, inside the DB): Members are looked up by id — a hash/B-tree index on the primary key, given to you by SQLite. Groups are listed (a scan over ~40 rows — trivially cheap; no index needed for 40 rows, and adding one would be over-engineering). The sign-ups table gets an index on group_id because you query “who’s in this group” constantly — that’s the tree-index decision from Week 12, made on a real query pattern.

Step 3 — The architecture in one paragraph

A FastAPI server exposes a JSON API (list groups, sign up, view roster). Data persists in a single SQLite file with three tables — members, groups, signups — where signups has a uniqueness constraint on (member_id, group_id) and capacity is enforced inside a transaction. A plain HTML/CSS/JS front end calls the API with fetch(). The whole thing runs as one process reading one file, maintainable by one person.

That is an architecture document’s core. Notice every choice traces back to a named constraint.

Step 4 — Where I’d choose differently if a constraint changed

This is the part that proves you understand the method and not just the answer. State it explicitly:

  • If the user count were 120,000 instead of 1,200 (a denomination-wide tool), the write burst would overwhelm SQLite’s single writer. → Migrate to Postgres for real concurrent writes (MVCC). The consistency requirement is unchanged; the scale of contention changed. (Week 12’s exact lesson.)
  • If sign-ups were truly simultaneous at high volume (concert-ticket-style, thousands grabbing seats in the same second) → Postgres with row-level locking or a SELECT ... FOR UPDATE, and possibly a queue in front. The consistency need just got sharper.
  • If the data were free-form — say each group could have wildly different custom fields (some need childcare info, some need a skills survey, some need nothing) → that’s a genuine document shape, and Mongo would start to earn its keep. But for fixed fields like ours, relational is right.
  • If the team only knew JavaScript → the same architecture in Node instead of FastAPI. The DB and front-end decisions don’t change. The server choice follows the team.

Coach’s Note — Read that last bullet list again. The method produced a specific stack — but the method is the lesson, not the stack. If you walked away from this section thinking “small-group tools use FastAPI + SQLite,” you missed it. What you should walk away with is the procedure: name the constraint, trace the tool to it, and know which constraint flip changes which choice. That’s why we do a second example next, with different constraints, that yields a different stack.


15.4 — A Second Example, Different Constraints, Different Stack

Same method. Different problem. Watch the stack change.

The problem: “A para-church ministry runs a daily devotional. Every morning they publish one devotional — a title, a passage, a few paragraphs, sometimes an image, sometimes an embedded audio clip, sometimes a list of discussion questions, sometimes none of those. They want a public site where anyone can read today’s devotional and browse the archive. Tens of thousands of readers a day; growing. Two staff, one of whom can write some JavaScript. Almost all traffic is reading; writes happen once a day when staff publish.”

The seven answers, fast

  1. Users: tens of thousands daily, public, growing. Real read scale.
  2. Read/write shape: wildly read-heavy, write-tiny (one publish per day by staff). The exact inverse balance of the sign-up tool’s burst, and even more lopsided toward reads.
  3. Consistency: almost none required. There’s no last-seat race, no money, no cap. A reader seeing a devotional half a second after it publishes is fine.
  4. Budget: small ministry, modest dollars, low ops appetite.
  5. Team: two staff, one writes some JS.
  6. Timeline: ongoing product, not a deadline crunch.
  7. What changes next: the shape of a devotional varies (sometimes audio, sometimes questions, sometimes neither). That variation is a real signal.

Let the stack fall out — and watch it differ

Database: The decisive constraints are (a) read-heavy, low-consistency and (b) varying document shape (#7). A devotional with optional audio, optional questions, optional image is genuinely document-shaped — modeling every optional field as nullable columns or extra join tables in SQL is the “awkward in SQL, natural in a document store” case from Week 13. → MongoDB is a defensible choice here, for this constraint, where it was the wrong choice for the sign-up tool. (Equally defensible: a relational store with a JSON column, or even flat files/static generation given how read-heavy and write-rare it is. The point is the reasoning, and that you can defend the line.)

Server: The staff member knows JavaScript, and the workload is many concurrent read connections — the I/O-bound, many-connections case the Node event loop is built for (Week 9 Hard tier). → Node.js. Different team, different workload, different server than the last example.

Front end: Still mostly content pages. Plain HTML/CSS/JS is still fine; the read-heavy nature even invites caching or static generation. No framework needed.

The contrast, on purpose

Sign-up toolDaily devotional
Decisive constraintwrite-consistency (capacity race)read-scale + document shape
ServerFastAPI (Python team, validation)Node (JS staff, many read connections)
DatabaseSQLite (single writer is fine at this scale; relational)Mongo (document-shaped, read-heavy, low-consistency)
Front endplain HTML/CSS/JSplain HTML/CSS/JS

Same method. Opposite stack on two of three layers. That is the proof. The lesson of this chapter is not any particular stack. The lesson is the procedure that produces the right stack from the constraints — and a procedure you can defend is worth more than an answer you memorized, because next year’s problem will have different constraints and the memorized answer will be wrong.


15.5 — MVP Scoping: Minimum Viable, Minimum Lovable, Gold-Plated

You have the stack. Now: what do you actually build first? This is where projects die — not from choosing the wrong database, but from trying to build everything at once and shipping nothing.

Three scopes, and you must be able to tell them apart:

  • Minimum Viable (MVP): the smallest thing that delivers real value to a real user. For the sign-up tool: list groups, sign up (with capacity enforced), see what’s full. That’s it. It already beats the paper sheet — that’s the bar for “viable.”
  • Minimum Lovable: the MVP plus the small handful of things that make people actually want to use it rather than tolerate it. A clear confirmation message. A roster the leader can read without squinting. Not features — polish on the core. The devotional’s “lovable” is that today’s reads fast and looks clean.
  • Gold-Plated: every feature anyone imagined. Waitlists, email reminders, attendance tracking, a leader dashboard with charts, dark mode, a mobile app. Most of it nobody asked for, all of it cost you, much of it never used. Gold-plating is the Babel failure — building big to make a name, not building well to serve.

The architect’s discipline is to ship minimum lovable and resist gold-plating until a real user asks for the next thing. How do you find the line? Count the cost.

Count the cost (Luke 14:28, again)

In Chapter 1 of this book, your very first project was Measure, Predict, Confirm, and the frame was Luke 14:28: “which of you, desiring to build a tower, does not first sit down and count the cost, whether he has enough to complete it?” That verse opened the book, and it closes the loop here. Counting the cost is not just for Big-O. It’s for features, too.

For every feature past the MVP, ask:

  1. What does it cost to build? (your hours, your timeline)
  2. What does it cost to maintain? (the 2 a.m. failure; the complexity budget)
  3. What does it cost to leave out? (the actual user pain of not having it)

If (3) is small and (1)+(2) are large, cut it. That is the cost-counting from Chapter 1, applied to scope. The builder who counts the cost finishes the tower. The one who doesn’t ends up with a half-built tower and onlookers saying “This man began to build and was not able to finish” (Luke 14:30). A shipped MVP beats an unfinished cathedral every single time.

Coach’s Note — The most expensive features are the ones an agent makes easy to add. Because they’re cheap to generate, you’ll be tempted to bolt on five of them “while I’m here.” Every one is now code you own, maintain, and debug forever. The agent’s speed is precisely what makes gold-plating dangerous now in a way it wasn’t before. Counting the cost of scope is more important in the agentic era, not less. The architect’s restraint is the scarce resource.


15.6 — Where Agentic AI Accelerates vs Where the Human Must Decide

This is the book’s central claim, made as sharp as I can make it. We have been circling it for fifteen weeks. Here it is in one table.

The agent is excellent at…The human must own…
Building a well-specified module to your specWriting the spec — deciding what the module should do
Scaffolding a project (dirs, config, boilerplate)The constraint analysis (the seven questions of §15.1)
Generating CRUD endpoints from a schemaThe tool choice — which server, which database, and why
Writing migrations from a data model you gave itThe data model itself — the tables, the relationships, the keys
Drafting tests for behavior you describedDeciding what behavior is correct in the first place
Writing the front-end DOM code for a layout you specifiedThe consistency / security judgment (the last-seat race; parameterized SQL)
Refactoring within a module without changing behaviorIs this even the right thing to build?” — the scope and the architecture
Fast, fluent, tireless typingKnowing when the fast, fluent answer is subtly, dangerously wrong

Look at the left column: it’s all execution of a well-defined task. Look at the right column: it’s all judgment under constraint. That division is not an accident of today’s models being imperfect. It is structural. The agent has no access to your users, your budget, your team, your timeline, your liability if the last seat double-books. It cannot count a cost it cannot see. The judgment lives with the person who can see the constraints — and that is you.

This is exactly why the Phase 2 projects were shaped the way they were. Every single one required an agent-log.txt and a human architecture decision the agent could not make:

  • P9/P10 asked you to choose Node vs FastAPI for three different hypothetical constraints. The agent can build either; only you can choose which one a constraint deserves.
  • P11 made you find SQLite’s write-contention limit and name the exact constraint that pushes to Postgres. The agent will write SQLite code; it won’t tell you when SQLite is the wrong tool.
  • P12 made you justify the migration, because reaching for Postgres needlessly is its own mistake — a judgment, not a code-gen task.
  • P13 made you choose relational vs document and defend it. That is the architecture decision in its purest form.

The projects were built so the agent couldn’t do your part. That was deliberate. The course is one long argument that the architect’s judgment is the irreducible human contribution — and the projects are the proof.

Coach’s Note — Here is the trap, stated plainly. An agent will cheerfully do the things in the right column badly. Ask it to “build a small-group sign-up tool” and it will pick a stack, invent a schema, and write a capacity check — confident, fluent, and possibly racy on the last seat. It will not stop and say “wait, what’s your write-concurrency constraint?” You have to stop and ask that. The danger of agentic AI is not that it refuses the judgment calls. It’s that it makes them silently, with total confidence, and hands you a polished thing that’s wrong in exactly the place you didn’t look. Reading the code (Coding 2, Chapter 1) and owning the architecture (this chapter) are the two defenses. You have both. Use them.


15.7 — Deployment Realities: “Runs on My Machine” vs “Runs”

A brief, honest word — because the capstone runs on your machine, and you should know the gap between that and a thing real people use.

“It runs on my machine” is a smaller claim than it sounds. Here is what stands between your laptop and a thing on the internet:

  • Ports. Your server listens on a port (you’ve used localhost:8000, localhost:3000). On a real host, something has to route public traffic to that port, usually through a reverse proxy, and the port your code uses is read from an environment variable, not hardcoded. The honest move even now: read the port from os.environ/process.env, never hardcode it.
  • Environment variables and secrets. Your database path, API keys, passwords — these must come from the environment, never be committed to git. “It works because the password is in my source file” is “runs on my machine,” and it’s also a security incident waiting to happen. Use environment variables now so the habit is built.
  • Dev vs prod. In development you run one process, see errors in your terminal, restart by hand. In production the process must restart itself when it crashes, log somewhere you can read later, and survive the machine rebooting. The code is the same; the operational wrapper is entirely different.
  • The database is a server too. SQLite travels with your app (it’s a file). Postgres and Mongo are separate running processes that, in production, live on a different machine with their own backups, their own credentials, their own uptime. “Runs on my machine” usually means “and the database is also on my machine,” which is not how production works.

Here is the honest boundary: real deployment — hosting, reverse proxies, process managers, containers, CI/CD, monitoring — is a whole subject, and it is a later one. This book is not a DevOps course (the README says so plainly). I am not going to teach you Kubernetes. What I am telling you is that the gap exists, that “runs” is a bigger word than “runs on my machine,” and that the two cheap habits above — read config from the environment, keep secrets out of git — cost you nothing now and save you from the two most common rookie deployment disasters later.

Coach’s Note — When someone says “but it works on my machine,” the senior engineer’s reply is “great — now we know it works on exactly one machine in exactly one configuration with exactly your environment.” That’s a real data point and a small one. The architect designs toward the day it has to run somewhere else: config from the environment, secrets out of the source, no hardcoded paths or ports. You don’t have to deploy to production this week. You do have to stop writing code that can only run on your machine.


15.8 — Final Prep: Write the Architecture Document FIRST

Project 14 is next week. It is take-home, open-AI (agentic), with a 60-minute live integration session. The grader reads four things: your architecture doc, your code, your agent-log.txt, and your reflection.docx. The architecture document is graded most of all. This section is how to use the week well.

The one rule: the architecture doc comes before the code

Not after. Not “I’ll write it up once it works.” First. Here’s why that order is non-negotiable:

  1. The architecture doc is the constraint analysis. If you write it first, you’ve done §15.1 before you’ve committed to a single tool. If you write it last, it’s fiction — a justification reverse-engineered from whatever you happened to build.
  2. The doc is what you hand the agent. A clear architecture doc is a clear set of specs, and a clear spec is what makes the agent useful instead of dangerous. Vague doc → vague prompts → confident, wrong code.
  3. Writing it first is the only way to catch a bad tool choice while it’s still free to change. Catching it after you’ve built on Postgres is expensive. Catching it on paper is free. (Count the cost — §15.5.)

What the architecture document must contain

One page. No more. It must have:

  1. The problem, in one paragraph. What does this serve, for whom?
  2. The seven constraints (§15.1), answered explicitly. Users/scale, read/write shape, consistency, budget, team, timeline, what-changes-next.
  3. The stack, with each choice traced to a constraint. “FastAPI because the team is Python and validation matters. SQLite because the write burst is small and the ops budget is zero. Plain JS front end because state complexity is low.” Every choice gets a because, and every because points back to a constraint.
  4. Where you’d choose differently if a constraint changed. At least two flips (§15.3 Step 4). This is what proves you understand the method, not just the answer. The Hard tier lives here.
  5. The MVP scope line (§15.5). What’s in the minimum-lovable build and what you’re explicitly cutting for now, and why.

That’s it. One page, but every sentence load-bearing. A template lives in code/architecture-doc-template.txt, and a worked-through example (the sign-up tool from §15.3) is in code/sample-architecture-doc.txt. Use the constraints worksheet in code/constraints-worksheet.txt to answer the seven questions before you write the doc.

The week’s plan

  • Now: read Project 14 (next chapter) and pick a scope from the approved list. Don’t pick the most ambitious one; pick the one you can ship lovable.
  • This week: do the Reps in the exercises. They are architecture drills — given constraints, choose and defend a stack. They are the exact muscle the final’s architecture doc tests. Do them timed.
  • Before the live session: write a full architecture doc for your chosen scope, first, on paper. Then — and only then — start directing the agent against it.

Coach’s Note — The single best predictor of a strong capstone is a strong architecture doc written before the code. I have graded enough of these to tell you with certainty: the students who write the doc first ship coherent systems and defend them easily in the live session. The students who code first and document after produce a tangle they can’t explain when I ask “why this database?” — because the honest answer is “it’s what the agent picked.” Don’t be that student. Write the doc. Make the choices. Then let the agent build what you specified. That sentence is the whole book.


15.9 — Common Bugs (Architecture Edition)

These are not syntax bugs. They are judgment bugs — the architecture mistakes that cost the most and show up most in capstones.

Bug: You chose the technology first and reverse-engineered constraints to justify it. Example: “I’ll use Postgres” → then writing an architecture doc that pretends a 12-user tool needs MVCC. Fix: Constraints first, always. If you can’t name the constraint that demanded the tool, you don’t need the tool. Write the seven answers before naming a single technology.


Bug: You let the agent choose the database silently and never made the call yourself. Example: Prompting “build me a backend for X,” accepting whatever stack it scaffolds, and having no answer when asked “why this one?” Fix: The tool choice is the right column of §15.6 — it’s yours. Decide it in the architecture doc, then tell the agent what to use.


Bug: You enforced a capacity/uniqueness constraint outside a transaction, creating a race condition. Example: SELECT count(*) then separately INSERT — two simultaneous requests both read “under cap” and both insert. Fix: Put the check-and-write in one transaction, or use a database uniqueness constraint and handle the conflict. The consistency judgment is the human’s (right column), and it’s exactly where the agent ships silent bugs.


Bug: You gold-plated — built five features nobody asked for and never shipped the core. Example: A sign-up tool with a waitlist, email reminders, and a chart dashboard, but the basic capacity enforcement is still broken. Fix: Ship minimum lovable. Count the cost of every feature past the MVP (§15.5). Cut the ones whose cost-to-omit is small.


Bug: You hardcoded a port, a path, or a secret, so the system only runs on your machine. Example: DB_PATH = "/litman-books/Users/you/groups.db" or an API key pasted into source and committed. Fix: Read config from environment variables. Keep secrets out of git. Two cheap habits (§15.7) that prevent the two most common deployment disasters.


Bug: You over-architected for scale you’ll never reach. Example: Microservices, a message queue, and a Postgres cluster — for a 40-group church sign-up used twice a year. Fix: Architect for the change you can see coming (constraint #7), not every change you can imagine. Over-architecting is the Babel failure: building big for its own sake. Build well, to the measure of the actual problem.


15.10 — Reps

Open the exercises. This week’s reps are architecture and decision drills — not much new code. Each one hands you a problem with explicit constraints and asks you to choose a stack and defend it, then re-decide when a constraint flips. That is precisely the muscle Project 14’s architecture document tests.

A preview:

  • Rep 1 — Answer the seven constraint questions for a given scenario, cold.
  • Rep 3 — Given three scenarios, choose Node vs FastAPI for each and justify from the constraint.
  • Rep 6 — Choose SQLite vs Postgres vs Mongo for three scenarios; name the deciding constraint.
  • Rep 9 — Take one architecture and flip a constraint; show which choices change and which don’t.
  • Done? One Last Thing. — Write a full one-page architecture doc, from scratch, for a brand-new problem, in 20 minutes.

Do every one. Do them timed. The final is a timed build, and the architecture doc is the part it grades most.


15.11 — This Week: Final Prep, Not a Project

There is no new project this week. Project 14 — the capstone — is in Chapter 16, and its full spec is Project 14.

This week’s work is twofold:

  1. Do the architecture drills in the exercises, timed, until choosing-and-defending-a-stack is finger memory.
  2. Write a real architecture document, first, for the capstone scope you’ll pick. Use the template and worksheet in code/. This is the single highest-leverage thing you can do before the final, because it’s the deliverable the final grades most of all.

The capstone is open-AI and agentic. That is not because the AI makes it easy — it’s because, after fifteen weeks, directing the agent is part of the work, and the exam would be dishonest if it pretended otherwise. The agent will build your modules. You decide which modules exist, on what stack, under what constraints, scoped to what’s lovable. Write the doc first. Then direct.


15.12 — Coach’s Final Word for Week 15

This is the chapter the whole book was built to reach.

Fifteen weeks ago you couldn’t say what a list cost. Now you can architect a whole system from its constraints — name the users, the read/write shape, the consistency need, the budget, the team, the timeline, the next change, and let the right server, the right database, the right front end fall out of those answers. You can say why SQLite is right here and wrong there. You can spot the last-seat race the agent shipped silently. You can tell minimum-lovable from gold-plated and ship the one that serves. That sight — seeing the structures, the server, the database, the front end, and the seams between them, and knowing what each costs before you build — is what an architect has and a coder doesn’t.

And here is the thing the whole book has been arguing: the agent can’t do that part. It can build any module you specify, faster than you can type. It cannot count a cost it cannot see, choose under constraints it doesn’t know, or decide whether the thing is worth building at all. That judgment is the irreducible human contribution. It is also, not coincidentally, the part that takes a vocation seriously — building well, not just big; building to a measure, for the people who will live in what you make. Babel built big for the builder’s name and scattered into noise. The New Jerusalem was built to a measure, for those it would shelter. Let each one take care how he builds.

Next week you build one. Small, real, internet-aware, architected on purpose and defended out loud. Write the doc first. Make the choices. Direct the agent against your spec. Ship something lovable, not gold-plated. And stand behind every decision, because they’ll be yours.

You’re ready. You’ve been getting ready for fifteen weeks.

See you on Monday.


Up next: Read the exercises — the architecture and decision drills — and do them timed. Then write a full architecture doc for your capstone scope using the code/ templates. Then open Chapter 16 and Project 14 — the capstone. Previous chapter: Chapter 14.