Quiz — Chapter 34: Writing for Computer Science
Target: 70%+ before moving on. Answers and explanations are hidden under each question—try first, then check.
Section 1 — Multiple Choice
1. What is the single most important principle for writing a code-review comment?
- A) Be thorough—comment on everything you notice, large and small, with equal emphasis
- B) Be diplomatic—soften every comment so the author never feels criticized
- C) Critique the code, not the coder—be specific about the code's behavior and aim at the code, not the author
- D) Be fast—approve quickly so you don't block the author
Answer
**C.** A review comment is read by the human who wrote the code, and the move that makes review work is separating the *code* from the *coder*: describe what the code *does* ("this returns `None` on empty input, line 14"), not what the author *failed* to do ("you forgot the empty case"). (A) is wrong because flat, equal-weight thoroughness buries the real bug among nits—you must label blocking vs. `nit:`. (B) confuses kindness with softness; the goal is *candor without cruelty*, and a reviewer who waves through real bugs to avoid friction fails just as badly as a cruel one. (D) sacrifices the code for speed. See §34.1 and the Threshold Concept.2. What three things should a pull-request description tell the reviewer?
- A) The author's name, the date, and the number of files changed
- B) What changed, why, and how to test it
- C) The full source code, the test results, and the deployment plan
- D) The history of the project and the team's coding standards
Answer
**B.** The diff already shows *what changed* line by line; the description must supply what the diff can't: **what** changed (a human-graspable headline), **why** (the intent—you can't evaluate an implementation without knowing its intent), and **how to test** (so the reviewer can *verify*, not just read). (A) is metadata the tool already shows. (C) is redundant (the diff) or overkill. (D) belongs in a contributing guide, not every PR. See §34.2.3. Why is a PR description's "how to test" section the most valuable and most-skipped part?
- A) Because writing tests is the hardest part of programming
- B) Because it lets the reviewer verify the change works rather than merely inspect whether the code looks right—catching bugs reading alone can't
- C) Because reviewers are legally required to test every change
- D) Because it makes the PR description longer and more impressive
Answer
**B.** Reading code confirms it *looks* right; running the test confirms it *is* right. A reviewer who can verify catches the dangerous class of bug—code that works but does the wrong thing, or that breaks something else—which is invisible to inspection alone. It's the same principle as [Chapter 25](../../part-05-software-data-writing/chapter-25-readme-api-docs/index.md)'s "every example must be runnable." (A) is unrelated (the section gives the command to run *existing* tests). (C) is false. (D) inverts the value—it's about enabling verification, not length. See §34.2.4. What is the single most valuable thing to include in a bug report?
- A) An expression of how urgent and frustrating the bug is
- B) The reporter's theory about what part of the code is responsible
- C) A minimal, runnable reproduction—the fewest steps or smallest snippet that reliably triggers the bug
- D) A list of every feature the reporter uses
Answer
**C.** A minimal reproduction lets the developer *see* the bug on their own machine immediately—the prerequisite to fixing anything—and the act of minimizing it often reveals the cause. (A) adds pressure without information ("broken, ASAP" is the useless report). (B) can help but is often wrong and isn't a substitute for a repro the developer can run. (D) is noise. See §34.3.5. A bug report should always include "expected vs. actual" behavior. Why are both halves necessary?
- A) To make the report look more professional
- B) Because a bug is precisely a gap between what should happen and what does—naming only one half leaves the developer guessing the other
- C) Because the developer can't read code without it
- D) Because "actual" alone is enough; "expected" is just politeness
Answer
**B.** A bug *is* the gap between expectation and behavior; "it's wrong" states neither half clearly. Stating the expected ("should return Feb 29") and the actual ("returns Feb 28") turns a vague complaint into a specific, checkable claim and tells the developer what success looks like. (A) misses the function. (C) is unrelated. (D) is exactly backwards—without "expected," the developer may not even agree there's a bug (maybe the behavior is correct and the reporter's expectation was wrong). See §34.3.6. What makes an acceptance criterion testable?
- A) It uses positive, encouraging language about the user experience
- B) It states a concrete, checkable condition (often Given-When-Then) that someone can mark pass or fail
- C) It is written by a developer rather than a product manager
- D) It describes the feeling the feature should produce in the user
Answer
**B.** A testable criterion names a starting context, an action, and a required outcome ("Given an email matching no tickets, when the agent searches, then an empty-state message is shown") that a tester can objectively verify. (A) and (D) describe *feelings* ("intuitive," "delightful") which are subjective and unfalsifiable—the exact failure the chapter warns against. (C) is irrelevant—who writes it doesn't determine testability. See §34.4.7. What is the difference between a user story and its acceptance criteria?
- A) They're the same thing with different names
- B) The story states the need (who, what, why); the acceptance criteria are the specific testable conditions that define "done"
- C) The story is for developers; the criteria are for users
- D) The story is written after the feature ships; the criteria before
Answer
**B.** A user story captures *who* wants something, *what*, and *why* ("As a support agent, I want to search by email so I can find history"); the acceptance criteria are the contract for "done"—the concrete, testable conditions the feature must satisfy. The story says what to build and why it matters; the criteria say exactly what counts as finished. (A), (C), and (D) all misstate the relationship. See §34.4.8. What is the most important reason to write a design doc before building something substantial?
- A) Because managers require documentation for compliance
- B) Because writing the design forces you to think it through, surfacing flaws while they're cheap to fix on paper rather than expensive to fix in shipped code
- C) Because the design doc is the deliverable that gets shipped to users
- D) Because it's faster to write prose than to write code
Answer
**B.** The doc *is* the engineering, done in the cheapest medium: a flaw caught on paper costs an afternoon; the same flaw caught in week three of implementation costs the weeks already built on top of it. Writing forces the design to be explicit and complete enough to critique, and lets reviewers catch problems in parallel. (Theme 1: writing is thinking.) (A) is a side effect, not the point. (C) is false—the code ships; the doc's job is mostly done once it's shaped what got built. (D) misstates it—it's not faster to *write*, it's faster *overall* because it avoids building the wrong thing. See §34.5.9. A design doc opens with "We should migrate to a microservices architecture." What's wrong with starting this way?
- A) Nothing—stating your recommendation up front is good BLUF practice
- B) It leaps to a solution before establishing the problem, trapping reviewers into evaluating a predetermined answer and killing the alternatives the doc exists to weigh
- C) Microservices are always the wrong choice
- D) Design docs should never contain recommendations
Answer
**B.** A design doc must state the *problem* (quantified) before any solution; opening with the solution ("migrate to microservices") forces the reader to evaluate an answer to a question never asked and shuts down the alternatives-considered section. (A) confuses a *report's* BLUF (lead with the conclusion for a decided matter) with a *design doc's* job (deliberate among options—the problem must come first). (C) overstates—the issue is structure, not the merits of microservices. (D) is false; docs recommend, but only after framing the problem. See §34.5.10. What does "blameless" mean in a blameless postmortem?
- A) No one is named anywhere in the document
- B) The incident is treated as no one's fault and quietly forgotten
- C) The analysis targets the system and the conditions that let the error reach production, not the individual who made the mistake
- D) Only managers, not engineers, are allowed to write it
Answer
**C.** Blameless means the root-cause *analysis* asks "why was it *possible* for this error to reach production?" and targets system conditions (no test for the default, a gap in the pipeline), not "who messed up." It does *not* mean anonymous—(A) is wrong; the author and timeline can name people, but the analysis aims at the system. (B) is wrong—blameless postmortems are taken very seriously and produce concrete fixes. (D) is invented. See §34.6.11. Why is "the engineer should have been more careful" a useless corrective action in a postmortem?
- A) Because it's too harsh on the engineer
- B) Because it asks a human to stop being human while changing nothing about the conditions that allowed the error—so the same failure recurs
- C) Because corrective actions must always be about tooling, never about people
- D) Because it's too short to count as a real action item
Answer
**B.** "Be more careful" changes no system condition; humans will keep making mistakes, so an unchanged system will produce the same failure again. A useful corrective action changes the system (a test, a guard, a check, a process) so the error *can't* silently ship—and it has an owner and a date. (A) is true but secondary; the deeper problem is that it *doesn't work*. (C) overstates—process changes can involve people, but they must change the system, not exhort. (D) misses the point entirely. See §34.6.12. The chapter says "critique the code, not the coder" and "debug the system, not the human" are the same threshold. What is the shared underlying move?
- A) Always be polite, regardless of the situation
- B) Separate the artifact or system from the person, so the critique produces improvement instead of defensiveness
- C) Avoid all conflict on a software team
- D) Let people off the hook for their mistakes
Answer
**B.** Both moves separate *the work* (code, system) from *the person*, which is what makes the writing produce the outcome you want—better code, fewer outages—rather than defensiveness and hidden mistakes. (A) confuses the move with mere politeness; it's about *where you aim*, and you can aim a *hard* objection at the code. (C) is wrong—candid critique is the goal, just aimed correctly. (D) is the opposite—blameless postmortems and code review *increase* real accountability by making the system better, while removing the fear that hides problems. See the Threshold Concept and §34.6.Section 2 — True/False with Justification
State true or false and justify in one sentence. The justification is where the learning is.
T1. A kind code-review comment is one that avoids pointing out problems so the author doesn't feel bad.
Answer
**False.** Kindness in review is *candor without cruelty*—saying the true, hard thing about the code clearly and aimed at the code; a reviewer who waves through real bugs to spare feelings fails just as badly as a cruel one, having optimized for comfort over the code. (§34.1)T2. The code diff in a pull request contains enough information for a reviewer to evaluate the change, making the description optional.
Answer
**False.** The diff shows *what* changed but never the *intent*, and you can't tell whether an implementation is correct without knowing what it's supposed to do—so the description must supply the why (and the how-to-test), or the reviewer reverse-engineers intent from implementation, which is backwards and error-prone. (§34.2)T3. Building a minimal reproducible example for a bug report is purely a courtesy to the developer; it does nothing for the reporter.
Answer
**False.** Minimizing the repro is itself debugging—stripping a 500-line program to the 3 lines that still fail frequently reveals the cause (often that the bug was in the reporter's code, or pins it to one specific input), so it serves the reporter, not only the developer. (§34.3)T4. "The search should return results quickly" is a usable acceptance criterion as long as everyone on the team agrees informally on what "quickly" means.
Answer
**False.** "Quickly" is untestable—informal agreement evaporates and can't be checked pass/fail; a usable criterion states a concrete number ("results return in under 500 ms at the 95th percentile on a 1M-row dataset") that a tester can verify and a developer can build to. (§34.4)T5. A blameless postmortem means the document never names the person involved in the incident.
Answer
**False.** Blameless refers to where the *analysis* aims (the system, not the person), not to anonymity—the author and the timeline can name people; what matters is that the root cause targets the conditions that let the error reach production, not the individual's competence. (§34.6)T6. Skipping a design doc and starting to code immediately is usually faster overall for a substantial change.
Answer
**False.** It's the planning fallacy: a flaw caught on paper costs an afternoon, while the same flaw caught in week three costs the weeks already built on top of it plus the rework—so for non-trivial work the doc *is* the engineering, done where mistakes are cheap, and is usually faster overall. (§34.5)Section 3 — Short Answer
A model answer and a one-line rubric follow each.
S1. In one or two sentences, explain why "critique the code, not the coder" is not merely a matter of politeness but a practical requirement for good code review.
Model answer + rubric
**Model:** Aiming a comment at the coder ("you should know better") provokes defensiveness and teaches people to stop submitting risky-but-valuable changes and stop telling each other the truth, which degrades the code over time; aiming it at the code ("this returns `None` on empty input") describes a fact two peers can fix together, producing the better code that is the actual goal. **Rubric:** Credit for (1) the person-frame causes defensiveness / hidden problems, (2) the code-frame produces the actual outcome (better code), i.e., it's about *what works*, not manners. (§34.1)S2. List the five things a bug report needs for a developer to act on it.
Model answer + rubric
**Model:** (1) a one-line summary of the specific misbehavior; (2) steps to reproduce (ideally a minimal, runnable snippet); (3) expected vs. actual behavior; (4) the environment (software version, language/runtime, OS); (5) evidence (full error message/stack trace, screenshot, logs). **Rubric:** All five for full credit; "steps to reproduce" and "expected vs. actual" are the two the chapter stresses most. (§34.3)S3. Explain the difference between the proximate cause and the system (root) cause of an incident, using a concrete example.
Model answer + rubric
**Model:** The proximate cause is the immediate trigger ("a wrong config was deployed"); the system root cause is the condition that *let it happen* ("the deploy pipeline allowed an unreviewed config to reach production")—reached by repeatedly asking "why was that possible?" until you arrive at something you can change. Example: proximate = "the engineer forgot the database index"; system = "there's no automated check that flags a new query pattern lacking an index, and CI tested against data too small to expose the slowness." **Rubric:** Credit for a clear proximate-vs-system split tied to a concrete case, and for naming that the system cause is the one you can actually *fix*. (§34.6)S4. Why should acceptance criteria explicitly cover the empty/no-results case and the error case, not just the happy path?
Model answer + rubric
**Model:** Because if the criteria specify only the happy path, the behavior of the edge cases gets decided by accident—a developer makes an arbitrary choice at 2 a.m. (an error instead of a friendly empty state), and the mismatch surfaces in a demo; writing the edge-case criterion forces the *product* decision to be made on purpose, and the edge cases are exactly where vague criteria silently leave gaps (the same "document the failure, not just the success" instinct as [Chapter 25](../../part-05-software-data-writing/chapter-25-readme-api-docs/index.md)'s API errors). **Rubric:** Credit for (1) unspecified edge cases get decided by accident/badly, (2) writing the criterion forces a deliberate decision. (§34.4)S5. Explain why blame in a postmortem is self-defeating—why it makes future incidents more likely rather than less.
Model answer + rubric
**Model:** If postmortems hunt for a culprit, engineers learn to hide mistakes, omit details that make them look bad, and stay quiet during the next incident—which degrades the *information* every future postmortem depends on, so the team can't find and fix the real system causes, and the same class of failure recurs; blamelessness trades the satisfaction of finding fault for the truthful information needed to actually prevent recurrence. **Rubric:** Credit for the mechanism: blame → people hide information → can't fix the system → recurrence. (§34.6)Section 4 — Applied Scenario
A small writing task, graded by rubric.
A1. Rewrite this code-review comment to be specific, kind, and aimed at the code, with a path forward and a weight label. The real concern: the code builds a SQL query by string-concatenating user input, which is a SQL-injection vulnerability.
"Wow. Never concatenate user input into SQL, ever. This is a textbook injection hole. I can't believe this got written. Use parameterized queries like everyone has known to do for twenty years."
Rubric
Score 0–2 each: - **Specific:** Names the exact line and the concrete behavior (user input concatenated into the query string)? - **Aimed at the code:** Describes the vulnerability the code creates, not the author's competence ("I can't believe this got written" must go)? - **Path forward:** Points to parameterized queries / prepared statements, ideally with a pattern or example? - **Weight:** Clearly labeled blocking (a security hole is not a `nit:`)? - **Tone:** Candid about a serious issue without the contempt ("twenty years," "I can't believe")? A strong answer keeps the seriousness (this *blocks*; it's a security issue) while removing every word aimed at the person. Example: *"Blocking — security: this builds the query by concatenating `user_input` into the SQL string (line 31), which is a SQL-injection vector. Use a parameterized query instead: `cursor.execute('SELECT … WHERE email = %s', (user_input,))`. We do this in `repo.py:88` if you want a pattern. Happy to pair if useful."*A2. Write a short blameless postmortem (summary + timeline + root cause + two action items) for this incident: a scheduled job that deletes expired records accidentally deleted 4 hours of valid records because a timezone mismatch made it compute the "expired" cutoff wrong. The job was deployed by an engineer named Lin; recovery took 25 minutes via a backup restore.
Rubric
Score 0–2 each: - **Summary:** One or two sentences stating what happened and the impact (valid records deleted, restored from backup)? - **Timeline:** A neutral, time-ordered record of events, kept separate from the analysis? - **Root cause = system:** Traces the *system* cause (e.g., "the cutoff calculation used local time while records are stored in UTC, and no test covered the timezone boundary; the delete job had no dry-run or confirmation safeguard before destructive action"), *not* "Lin deployed a bad job"? - **Action items:** At least two that *change the system* (e.g., "add a dry-run mode that logs what would be deleted," "add a test for the timezone boundary," "require a soft-delete + grace period before hard delete"), each with an owner and a date? - **Blamelessness:** Could a reader tell *whose* code triggered it from the root-cause section? They should *not* be able to—the analysis aims at the system. (Lin may appear as author/owner; the analysis must not blame Lin.) Full marks (8/10+) require a system-targeted root cause and ownable, dated, system-changing action items. A root cause of "human error" or an action item of "be more careful" caps the score low—those are the exact failures §34.6 names.Scoring & Next Steps
| Score | What it means | Do next |
|---|---|---|
| < 50% | Core ideas haven't landed yet | Re-read §34.1 (code review) and §34.6 (postmortems)—the two threshold halves—then redo Section 1. |
| 50–70% | Partial grasp | Redo Part B of the exercises (the "revise this" tasks), especially B1 (harsh comment) and B4 (blameful postmortem). |
| 70–85% | Solid | Proceed to Chapter 35. Do the Project Checkpoint: produce one real developer-facing piece (rewritten review comment, PR description, bug report, or postmortem). |
| > 85% | Strong | Try the Deep Dive: exercises E1 (Google's code-review guide), E2 (postmortem-culture tradition), or E3 (draft a project's REVIEWING.md). |
The one test that matters more than this quiz: could the person at the center of your critique or your postmortem read it and feel informed and supported, not accused—while it still says the true, hard thing? If yes, you've crossed the threshold this chapter teaches.