Technical vision and design docs
A tech lead sets direction mostly in writing. This lesson shows you how to write a short technical vision for the next two quarters, how a design doc turns one big change into a decision, how to record that decision so nobody has to argue it again, and how to run design reviews that leave every engineer a little better.
By the end you can
- Write a one- to two-page technical vision: current state, where we are going, principles, non-goals and what we will not do
- Write principles that settle real arguments, and test them before you share them
- Structure a design doc around a decision: context, goals and non-goals, the design, alternatives, risks and rollout
- Record decisions as architecture decision records (ADRs) and supersede them when things change
- Run a design review that teaches: pre-read, questions before verdicts, "must fix" apart from "consider", decide and record
The everyday picture
A family plans a year of work on an old house. Before anyone buys a brick, they agree on one page: the house should feel brighter, the kitchen must work for a family of five, the plumbing walls stay where they are because moving them costs too much, no work during exam month, and no extension this year, however tempting. That page stops a hundred small arguments later.
For the biggest job, the kitchen, someone draws a plan and shows it to the plumber and the electrician before a wall comes down. They ask questions: "Where does the dishwasher drain?" Some of their points must be fixed before work starts; others are only good ideas. When a choice is made ("the socket goes left of the window, because the fridge needs the right side"), someone writes it on a sheet taped inside a cupboard door. Two years later, nobody moves the socket by accident. That is the whole lesson: a vision, a design doc for each big change, a review before the walls come down, and a written record of each decision.
A technical vision for two quarters
A technical vision answers one question for your team: when we make technical choices over the next six months, what are we trying to get to, and how do we choose? At team level it should fit on one or two pages. Longer visions read like plans, and nobody keeps a plan in their head. Write five parts, in this order.
- Current state, with numbers. What exists and what hurts. "About 1 stock count in 6 is interrupted by a Wi-Fi drop and has to be restarted" is a current state. "The app is a bit unreliable" is a mood.
- Where we are going. A picture of the end of the period that anyone in the team could check: "a count started on a scanner always finishes, online or not, and reaches the server within minutes of the connection coming back."
- Principles. Three to six rules for choosing between good options. This is the part people use every week, so it gets most of your care.
- Non-goals. Things a reasonable person could expect you to aim for, which you are choosing not to aim for this period. "Offline price changes" is a non-goal; "make the app slower" is not, because nobody wanted it.
- What we will not do. Actions you rule out, such as a rewrite, a new database on the scanners or a new service. This protects the team from its own enthusiasm.
A vision serves the product. Every line should trace back to an outcome that Imran, the product manager, cares about (daily counts of fast-moving items, stock accuracy above today's 82%) or to a risk the team carries. If a line traces to neither, it is a personal preference. The product direction itself lives in documents like Vision, strategy and why now; your vision says how the technology gets there.
How to write principles that work. A good principle passes three tests. First, a sensible team could choose the opposite. "The server decides the stock level" is useful, because a team could reasonably let the scanner decide. "Write high-quality code" fails, because nobody would choose the opposite. Second, it settles an argument you can already see coming. Third, a reviewer can check a design against it. Add one line under each principle saying what it means in practice: "so every scan is saved on the device before the screen confirms it."
Where the material comes from. You rarely invent a vision. Will Larson suggests writing about five design docs and pulling out what they share to get a strategy, then projecting strategies about two years forward to get a vision. As a new tech lead you can run that backwards: read the team's last few design docs, incident reviews and arguments, and write down the rules the good decisions already followed. Add what you learned in your first weeks (What a tech lead is (and is not)). Then share a draft for a week of comments, agree it with Imran and Ken, and look at it again each quarter.
Quick check
Which of these is the most useful principle for the Store app vision?
The idempotent upload rule is a real choice (a team could accept the risk of double counts to save effort), it settles a coming argument about retries, and a reviewer can check any design against it. The first and third options are things no team would argue against, so they decide nothing. The fourth is a delivery goal, which belongs in the plan or in "where we are going".
Design docs that get to a decision
A design doc is how one big change gets thought through by more than one head before it is built. Write one when any of these is true: the change is hard to reverse (a data model, a sync protocol, a public API), it will take more than a couple of weeks of work, it touches another team's system, or people already disagree about how to do it. A screen layout or a bug fix does not need one.
Malte Ubl's description of design docs at Google lists context and scope, goals and non-goals, the design, alternatives considered and cross-cutting concerns such as security and privacy. A version that works well for a team like yours has six parts:
- Context. What exists, what hurts, with numbers, and which line of the vision this serves. Keep it short and factual.
- Goals and non-goals. Goals you can check later ("an interrupted count finishes without rescanning a single item"). Non-goals stop the review from growing the scope ("two scanners counting the same aisle at the same time").
- The design. The data flow, the data model, the API and, most important, what happens in each failure: the app is killed, the battery dies, the upload is sent twice, the scanner's clock is wrong.
- Alternatives considered. At least two real ones, including "do nothing" or the cheapest fix. Ubl calls this one of the most important sections. If a doc shows only one option, nobody can tell whether it was chosen or was simply the first idea.
- Risks. Written as "if this happens, then that, so we will do this", each with an owner.
- Rollout. How it reaches users safely: a feature flag, a pilot store, the numbers you will watch, and how you turn it off.
Write the alternatives on the same rows. For each option, give the same four lines: what it is, what it costs, what it gives up, and which principle it fits or breaks. Reviewers can then compare options instead of reading three essays. Write at least one alternative you would be happy to lose to. If you cannot, you have not looked hard enough.
Who writes it. Usually the engineer who will build it, which is often not you. Writing the doc is how an engineer learns to own a design, so handing it over is one of the best stretch assignments you have (Delegation and mentoring). Your job is to agree the problem with them, review an early outline before they write ten pages, and make sure the review happens. Ubl suggests about 10 to 20 pages for a large project at Google and a 1- to 3-page "mini design doc" for smaller changes; for a team of six, 3 to 6 pages is usually plenty. Running a design review walks through the full anatomy, including the numbers and failure-mode sections.
Quick check
Sam's draft design doc for offline counts has a detailed design, a rollout plan and risks, but no alternatives. What is the best first response?
Without alternatives, reviewers cannot tell whether Sam's design wins or was only the first idea, and Sam misses the practice of comparing options. Writing it yourself fixes this doc but teaches nothing and quietly makes it your design. The team agreed on the goal (offline counts), not on the mechanism, so the alternatives are still open.
Recording decisions: ADRs
A design doc is a discussion. It can run to pages, and it goes stale once the work starts. The decisions inside it need a smaller, permanent home: the ADR. Michael Nygard proposed the format in a 2011 blog post: a title, a status, the context, the decision and its consequences, and the whole note should be one or two pages long. Most teams keep ADRs numbered in the code repository, so they travel with the code.
Three habits make ADRs work for a tech lead:
- One decision per record. The offline counts design produces at least two: how scans are synced (ADR-0012) and where they are stored on the scanner (ADR-0013). They may change at different times.
- Write it the same day. After a review, memories of why something was chosen fade within a week. The doc author writes the ADR; you check that the consequences include what was given up.
- Never edit an accepted decision. When you change your mind, write a new ADR and mark the old one superseded, as Nygard describes. A new engineer can then read the history and see why the system looks the way it does.
Write an ADR for decisions that are hard to reverse, and for decisions you expect someone to question in a year ("why don't we use a sync product?"). Small, easy-to-reverse choices go in the pull request description.
Quick check
Six months after ADR-0013 chose SQLite on the scanners, the team finds a better storage option and switches. What happens to ADR-0013?
Keeping the old record and linking the new one preserves the reasoning both times, which is the point of ADRs. Editing the old record looks tidy but erases why the first choice made sense, so someone may repeat the old debate. Deleting it loses the history completely, and a pull request is hard to find a year later.
Design reviews that teach
A design review has two goals: a better design and better engineers. If only the first happens, the team depends on you to catch every problem forever. Five methods give you both.
1. Pre-read. Send the doc at least two working days before the meeting and ask reviewers to leave comments in the doc. The meeting is then for the few comments that need a conversation. If people arrive without reading it, spend the first 10 to 15 minutes reading in silence instead of presenting slides. A presentation hides the gaps that reading finds.
2. Questions before verdicts. "What happens if the app is killed after scan 40?" lets the author find the gap, and teaches them to ask that question next time. "This loses data" gives the answer and teaches nothing. Use a verdict when a question did not land, or when time is short. Let the least experienced people speak first and speak last yourself. Once the tech lead has given an opinion, most people stop thinking and agree.
3. Label every comment. Must fix means the design cannot go ahead without a change: it loses or corrupts data, gets stock wrong, opens a security hole, breaks a principle in the vision, or has no way to roll back. Consider means a better idea that the author may take or leave. Question means "help me understand". Keep must-fix comments rare, because if everything blocks, nothing does.
4. Name the pattern. After a must-fix, say the general idea in one sentence and link it: "Any write that can be retried needs an idempotency key." The author fixes one bug; everyone in the room learns a rule they will use for years.
5. Decide and record. End with a clear outcome: approved, approved once the must-fixes are done, or another round needed. Say who decides if people still disagree (usually you or the doc owner) and by when. The author writes the ADR that day, and every open question becomes an action with an owner and a date. Running a design review has a full agenda and a question bank by area.
Quick check
In the review of offline counts, you notice that the design sets stock to the counted number and ignores sales made while the count was running. Joel, the junior engineer, has not spoken yet. What do you do?
A wrong stock level is a must-fix, so it has to be labelled as one, but asking it as a question after others have spoken gives Sam and Joel the chance to find it and remember it. Saying it first gets the fix but trains the room to wait for you. Leaving it for the pilot puts wrong stock into a real store. Softening a must-fix to "consider" hides a real defect.
Do it
Write the Store app's two-quarter vision, the numbers and the design doc for offline counts, the ADR it produces, and the review invite.
-
Write the vision on one page
Five parts, numbers in the current state, and a "so we will" line under every principle. Share it as a draft for a week, then agree it with the product manager and the engineering manager.
Markdown# Store app technical vision: Q1-Q2 | Owner: tech lead | Draft 2 ## Current state - Every workflow needs a live connection. About 1 count in 6 is interrupted by a Wi-Fi drop; staff restart it or write on paper. - Receiving takes about 51 min per delivery, 21 of them on workarounds. About 1 GRN in 12 is corrected later. Stock accuracy about 82%. - Each screen retries failed requests in its own way. ## Where we are going (end of Q2) - A count started on a scanner always finishes, online or not, and reaches the server within minutes of the connection returning. - Daily counts of fast-moving items are possible in all 320 stores. - Receiving is the next workflow on the same sync layer. ## Principles 1. The scanner never loses a scan. So we save every scan on the device before the screen confirms it. 2. The server decides stock. So scanners send what was counted and when; the server does the maths. 3. Every upload can be safely sent twice. So every write carries an ID made on the scanner, and repeats are ignored. 4. One sync layer for every workflow. So receiving reuses what counts build; no screen syncs on its own. 5. Boring technology, except where a principle forces otherwise. ## Non-goals (this period) - Offline price changes (scanners show the last price and its age) - Two scanners counting the same aisle at the same time ## We will not - Rewrite the app in native code - Add a new service: sync lives in the existing NestJS API -
Put numbers in the design doc's context
Say what the problem costs, with ranges, and mark every assumption so reviewers can challenge it.
OutputCounts per day (assumption: about 4 per store) = 320 x 4 = about 1,280 Interrupted by Wi-Fi (about 1 in 6) = 1,280 / 6 = about 210 Time lost per interrupted count (half of a 10-25 min count) = 5 to 12 min Staff time lost per day = 210 x 5 to 12 min = about 18 to 44 hours Cost at about $4 an hour = about $70 to $175 a day = about $26,000 to $65,000 a year Not counted: wrong stock from counts abandoned or written on paper, which is the bigger cost (items cut from app orders, about 9% today) -
Write the design doc around the decision
The engineer who will build it writes it. Keep the alternatives on the same rows, and give every failure case a line.
Markdown# Design doc: offline stock counts | Author: Sam, with Mira | Review: 14 Jan ## Context Counts fail when Wi-Fi drops (about 1 in 6). Serves vision principles 1-4. ## Goals / non-goals Goals: an interrupted count finishes with no rescans; no scan is lost or applied twice; synced within 5 min of the connection returning. Non-goals: two scanners on one aisle; offline price changes. ## Design - Count task (aisle, items, server time) downloaded before counting starts - Each scan saved to SQLite on the scanner: scan ID, item, qty, scanned at - Sync sends unsent scans in batches of 50; server ignores known scan IDs - Server: stock = counted qty + movements (sales, GRNs) since scanned at Failure cases: app killed (scans already saved); upload sent twice (ignored); scanner clock wrong (offset to server time taken at download) ## Alternatives (same rows) | Option | Cost | Gives up | Principles | | Online + retry | 1-2 wks | counts still fail offline | breaks 1 | | Upload at the end | 3-4 wks | a crash loses the count | breaks 1 | | Sync database tool | 6+ wks | new tech on 1,000 devices | breaks 5 | | Scan log (chosen) | 8-12 wks | more server logic | fits 1-5 | ## Risks If old app versions sync, then fields may be missing, so payloads carry a version and the server rejects unknown ones. Owner: Hugo. ## Rollout Feature flag. Ama's store (2 weeks), then 20 stores, then all 320. Watch: counts finished, sync failures, size of stock adjustments. Turn off: flag back to online counts; unsent scans are kept. -
Record the decision as an ADR the same day
One decision, one or two pages at most, in the repository next to the code. Say what you gave up.
Markdown# ADR-0012: Sync stock counts as a log of scans Status: Accepted (14 Jan). Supersedes: none. ## Context Counts must survive Wi-Fi drops (vision principle 1). Stock keeps changing during a count: sales at the till, deliveries received. ## Decision The scanner keeps every scan in a local log and uploads unsent scans in batches. Each scan has an ID made on the scanner; the server ignores repeats. The server applies each count as of the time it was scanned, then adds the movements since. ## Consequences + No scan is lost or applied twice; counts work offline. + Receiving can reuse the same log (vision principle 4). - More logic on the server; movements must be stored with exact times. - Scanner clocks must be corrected to server time at download. Revisit if: we need two scanners on one aisle. -
Send the review invite with the rules
Short, with the pre-read deadline, the labels and who decides.
MarkdownDesign review: offline stock counts | Thu 14 Jan, 45 min Pre-read: the doc, by Tue 12 Jan. Comment in the doc, labelled: MUST FIX - data loss, wrong stock, security, breaks a principle, no rollback CONSIDER - a better idea; Sam decides QUESTION - help me understand In the meeting: only comments that need talk. Newest team members first. Decider: Sam as owner; tech lead if we still disagree. ADR the same day.
Bring it to your team
Ask these about how your team decides, not only what it builds.
- Could each of us name two of our principles without looking, and has one settled an argument this month?
- Which line of the vision does this design doc serve?
- What other designs did we consider, including the cheapest fix, and why did each lose?
- What happens to this design when the app is killed, the upload is sent twice, or the clock is wrong?
- Which comments are must-fix, and are we sure each one really blocks?
- Who writes the ADR, and is it in the repository by the end of the day?
Red flags
- A vision with principles nobody could disagree with, and no non-goals.
- Design docs that show one option, or only appear after the code is written.
- Reviews where the tech lead talks first and most, and everyone else agrees.
- Every comment treated as blocking, or none of them labelled.
- A decision made in a meeting and written down nowhere; the same debate returns six months later.
- The tech lead writes every design doc.
Practice
Review a design doc excerpt
Hugo wrote this part of an early design for offline counts: "While offline, the app keeps the count in memory. When the connection returns, it uploads the whole count in one request. If the request fails, the app shows an error and the user presses Retry. The server sets each item's stock to the counted quantity." Write four review comments. Label each must fix, consider or question, phrase at least two as questions, and add one sentence naming the pattern behind each must-fix.
- A must-fix about losing the count if the app is killed or the battery dies, since it is only in memory
- A must-fix about a retry applying the count twice, with idempotency (an ID per scan or per upload) named as the pattern
- A must-fix about overwriting stock and ignoring sales and deliveries made during the count
- At most one "consider" item, such as uploading in batches instead of one large request
- At least two comments are questions, and none is about Hugo as a person
Show a model answer
1. Must fix (question): "What happens to a half-finished count if the app is killed or the battery dies while offline?" Pattern: save to the device before you confirm to the user (vision principle 1).
2. Must fix (question): "If the first upload reached the server but the reply was lost, what happens when the user presses Retry?" Pattern: any write that can be retried needs an idempotency key, so the server can ignore the repeat.
3. Must fix: "Setting stock to the counted number drops every sale and delivery since the item was scanned. Can the server apply the count as of the scan time and add the movements since?" Pattern: a count records the stock at one moment, so apply it at that moment.
4. Consider: "A one-hour count can be several hundred scans. Would batches of about 50 make failures smaller and progress visible?" Hugo decides.
Rewrite weak principles
A draft vision for the Store app has these principles: "1. Quality first. 2. Follow best practices. 3. Be scalable. 4. Move fast." It has no non-goals. The team is about to build offline counts, then offline receiving. Rewrite it as three principles that pass the three tests in this lesson (a sensible team could choose the opposite, it settles a coming argument, a reviewer can check a design against it), each with a "so we will" line, plus two non-goals.
- Each principle is a real choice with a sensible opposite
- Each has a "so we will" line that a reviewer could check in a design doc
- The principles fit offline counts and receiving, such as saving scans locally, the server deciding stock, or retries being safe
- The non-goals are things someone could reasonably expect, such as offline price changes
Show a model answer
1. The scanner never loses a scan. So we save every scan on the device before the screen confirms it. (The opposite, keeping data in memory to save effort, is a real option.)
2. The server decides stock. So scanners send what they counted and when, and the server calculates the adjustment. (A team could let the scanner calculate it.)
3. One sync layer for every workflow. So receiving reuses the sync built for counts, and no screen invents its own retries. (A team could let each screen sync separately to move faster.)
Non-goals: offline price changes this period; two scanners counting the same aisle at the same time.
Design doc, ADR or neither?
For each change, decide whether it needs a design doc, an ADR, both or neither, with one reason each: (a) moving the scan-confirmation button on the count screen; (b) choosing how scanners prove who they are to the API when they come back online; (c) changing the sync batch size from 50 to 100; (d) adding a second workflow, expiry checks, to the sync layer, which changes the server's data model; (e) Mira picks a date library for the count screen.
- (a), (c) and (e) need neither, because they are easy to reverse (a pull request description is enough)
- (b) needs at least an ADR because it is a security decision someone will question later; a short design doc if options are unclear
- (d) needs a design doc and an ADR because it changes the data model and other workflows depend on it
Show a model answer
(a) Neither: a layout change, easy to reverse; Leila and Mira decide. (b) Both: a short design doc comparing two or three options, then an ADR, because security choices are hard to reverse and will be questioned. (c) Neither: a setting you can change in the next release; note it in the pull request. (d) Both: a design doc because it changes a shared data model, and an ADR for the model change. (e) Neither: a library inside one screen is a two-way door; it goes in the pull request.
Check yourself
Two months into the period, Hugo proposes a new message-queue service for sync. The vision says "We will not add a new service." What should you do?
A vision guides decisions; it should change when new evidence appears, in the open and for a stated reason. Rejecting the idea by quoting the document turns the vision into a rulebook and teaches people not to raise ideas. Accepting on seniority skips the evidence. A quiet prototype creates a decision nobody reviewed.
Which review comment on a design doc teaches the most while still protecting the design?
The first is labelled correctly as blocking, lets the author find the problem, and names the rule for the whole team. The second protects the design but gives the answer away, so nothing is learned. The third hides a real defect behind a soft label. The fourth gives no reason and no label, so the author cannot act on it.
Ken asks why the Store app vision is only one page. He suggests adding every task for the two quarters so the team has everything in one place. What is the best reply?
A vision works only if people carry it in their heads when they make choices, which a task list prevents. Tasks change weekly and belong in the delivery plan. Hiding the principles in an appendix removes the most-used part. Refusing all change is wrong too; visions are reviewed every quarter.
Flashcards
Key takeaways
- A team vision fits on one or two pages: current state with numbers, where you are going, principles, non-goals and what you will not do. Every line traces to a product outcome or a risk.
- Good principles are real choices with a sensible opposite, settle arguments you can see coming, and can be checked in a design.
- Design docs exist for hard-to-reverse or contested changes. Show real alternatives on the same rows, every failure case, risks with owners and a rollout you can turn off.
- Record each decision as a short ADR the same day, and supersede it instead of editing it when things change.
- Reviews teach when there is a pre-read, questions come before verdicts, the lead speaks last, comments are labelled must fix or consider, and the review ends with a recorded decision.
Sources and further reading
- Documenting Architecture Decisions, Michael Nygard, 2011
- Design Docs at Google, Malte Ubl, 2020
- Writing an engineering strategy, Will Larson, lethain.com
- Choose Boring Technology, Dan McKinley, 2015
- Tanya Reilly, The Staff Engineer's Path, O'Reilly, 2022
- Will Larson, Staff Engineer: Leadership Beyond the Management Track, 2021