Exercises — Chapter 34: Writing for Computer Science
Writing is learned by writing. These exercises ask you to produce and revise the real writing of software work—review comments, PR descriptions, bug reports, acceptance criteria, and postmortems—not to pick answers from a list. Where a task is open-ended, a self-assessment rubric follows instead of a single "right" answer.
Difficulty: ⭐ approachable · ⭐⭐ moderate · ⭐⭐⭐ challenging · ⭐⭐⭐⭐ extension
Part A — Analyze This ⭐
Diagnose the following software-engineering writing. Name what works and what's broken, in the chapter's terms.
A1. A code-review comment reads: "This whole class is a mess. I can't even follow it. Rewrite it." The class is, in fact, hard to follow. Identify three things wrong with this as a review comment (separate from whether the underlying point is valid).
A2. A pull request has the title updates and an empty description. The diff touches eleven files. What does the reviewer have to do that a good description would have spared them, and what are the three sections the description is missing?
A3. A bug report says: "The app is really slow now, it wasn't before. Something you changed broke it. Please revert." List at least four specific pieces of information a developer needs that this report doesn't give.
A4. An acceptance criterion reads: "The notification system should send notifications reliably and in a timely manner." Name every untestable word in it, and say why each makes the criterion impossible to verify.
A5. A postmortem's root-cause section reads, in full: "Human error. The on-call engineer ran the wrong command." Why is "human error" a non-answer as a root cause, and what question should the postmortem have asked instead?
A6. Two review comments on the same line:
- (a) "Why is this a global? Globals are bad."
- (b) "This module-level _cache is shared mutable state—two requests parsing concurrently could race on it (line 30). Was it meant to be per-request? If global is intended, a lock would make it safe. nit-level if I'm misreading the threading model."
Which is useful and which isn't, and name three specific things (b) does that (a) doesn't.
A7. A design doc opens: "# Proposal: Adopt Kafka. We should migrate our event pipeline to Kafka for better scalability and decoupling." What's structurally wrong with starting a design doc this way, and which two sections of a good design doc does this opening pre-empt or skip?
A8. Release notes for version 4.0 read, in full: "Version 4.0 is here and it's amazing! Tons of improvements and bug fixes. Update now!" A user trying to decide whether to upgrade gets what from this? Name the Chapter 7 concept the notes violate and the one thing a user most needs that's absent.
Part B — Revise This ⭐⭐
Rewrite the following weak software-engineering writing. You're given the scenario and the flawed text; produce the improved version.
B1. The harsh code-review comment (the centerpiece revise task). Rewrite this review comment to be specific, kind, and aimed at the code, with a path forward and an appropriate weight label. The underlying concern is real: the function catches a broad except Exception and returns an empty list, hiding genuine errors from the caller.
"Are you serious with this error handling? You're swallowing every exception and returning an empty list like nothing happened. This is exactly the kind of thing that causes silent data loss in production. Do not do this. Have you not seen our style guide?"
Then write two sentences reflecting on what you changed and why your version will get a better result.
B2. The useless bug report (the second centerpiece task). Make this bug report actionable. You may invent plausible specifics, but you must add: a one-line summary, steps to reproduce (a runnable snippet or numbered steps), expected vs. actual, and environment. The underlying bug: a CSV export omits the last row when the file has no trailing newline.
"export is broken, rows are missing sometimes. happens with some files but not others. really need this fixed, it's affecting a customer report."
B3. The empty PR description. A developer opens a PR titled fix bug with no description. The change: it adds a null check in chronoparse's parse() so that parse(None) raises a clear TypeError with a helpful message instead of crashing deep in the tokenizer with a confusing AttributeError. Write a proper PR description with What / Why / How / How to test sections.
B4. The blameful postmortem. Rewrite this into a blameless postmortem analysis (you may keep it brief—focus on the root-cause section and the action items). The incident: a deploy took down the API for 18 minutes because a database migration locked a large table during peak traffic.
"The outage was caused by Marco running a migration during peak hours without thinking about the consequences. Marco needs to be more careful about when he runs migrations. We've reminded the team to use common sense about deploy timing."
Your rewrite must trace the system causes ("why was it possible to run a locking migration during peak traffic?") and produce at least three action items that change the system, each with an owner and a date.
B5. The vague acceptance criteria. A story reads: "As a user, I want to reset my password so I can get back into my account." Its only acceptance criterion is: "Password reset works smoothly." Rewrite this with four to five testable Given-When-Then acceptance criteria covering the happy path, the expired-link case, the unknown-email case, and at least one security consideration.
B6. The solution-as-problem design-doc opening. Rewrite this design-doc opening so it states the problem before any solution, quantifies it, and leaves room for alternatives:
"# Add a Redis cache layer. We're going to add Redis in front of the database to make the app faster."
Invent plausible specifics (what's slow, how slow, who's affected). Produce a proper Context/Problem section, then a one-line transition into where solutions (including Redis) will be evaluated.
B7. The review comment that's all nits, no priority. A reviewer left eight comments on a PR, all in the same flat tone: a variable rename, a missing space, a docstring typo, a real bug (an off-by-one that drops the last item), two more style preferences, a suggestion to extract a helper, and a "could use a comment here." The author can't tell what matters. Rewrite the real bug comment so it's unmistakably blocking, and show how you'd label the others so the author knows what's optional.
B8. Marketing release notes → useful ones. Rewrite these into release notes a user can act on. The actual changes in 2.0: adds a --dry-run flag, fixes a crash on empty input, removes the deprecated --legacy flag (breaking), and requires a config-file format change (breaking).
"We're thrilled to announce version 2.0, our biggest and best release ever, packed with powerful new capabilities and important fixes to make your experience even better!"
Part C — Write This ⭐⭐–⭐⭐⭐
Each scenario asks you to produce a complete document or section from scratch.
C1. A full code review of a small diff. Here is a short function (fictional) submitted in a PR. Review it: leave three to five comments, each specific and aimed at the code, with appropriate weight labels (nit: / blocking / question / praise). At least one comment should be a genuine question, and at least one should praise something.
def average(numbers):
total = 0
for n in numbers:
total += n
return total / len(numbers) # crashes on empty list
(Things you might notice: the empty-list division-by-zero; whether numbers could contain non-numbers; that the loop could be sum(numbers); whether a docstring/type hints would help; that the name is clear.) Write the comments as you'd leave them on a real PR.
C2. A complete PR description. Invent a realistic change to a project you know (or to chronoparse) and write its full PR description: an informative title, then What / Why / How / How to test / Notes. The change should be substantial enough to need all the sections (not a typo fix). Link a plausible issue number.
C3. An actionable bug report. Pick a real bug you've encountered in any software (or invent a realistic one) and write a complete report to the §34.3 standard: summary, steps to reproduce (minimal and runnable if possible), expected vs. actual, environment, evidence, and any narrowing you've done. Then add a sentence on how building the minimal reproduction did (or would) help locate the cause.
C4. A user story with acceptance criteria. Choose a feature (e.g., "filter a list," "upload a file," "schedule a reminder") and write it as a complete user story (As a… I want… so that…) plus four to six testable Given-When-Then acceptance criteria. You must include at least one empty/no-results case, one error case, and one concrete performance or limit criterion (a real number, not "fast").
C5. A blameless postmortem. Write a complete blameless postmortem for an incident—real (anonymized) or realistic. Include: summary, severity/duration, impact, a neutral timeline, a root cause traced to system conditions, what went well, and action items with owners and dates that change the system. Constraint: someone could read your root-cause section and not be able to tell whose mistake triggered the incident, because the analysis is aimed entirely at the system.
C6. A design-doc problem statement + alternatives. For a substantial change you can imagine (or have faced), write two sections of a design doc: a Context/Problem section (problem stated and quantified before any solution) and an Alternatives considered section laying out at least two options you rejected and why, plus the one you'd recommend. Do not write the full doc—just these two load-bearing sections.
Part D — Synthesis & Critical Thinking ⭐⭐⭐
D1. Find the flaw. A team lead argues: "Postmortems are a waste of time. When something breaks, we know who broke it and we tell them to fix their process. Writing a whole document is just bureaucracy." Using §34.6, explain precisely what this gets wrong—both about what a postmortem is for and about why "we know who broke it" is the wrong frame mechanically, not just morally.
D2. The same threshold, twice. The chapter claims that "critique the code, not the coder" and "debug the system, not the human" are the same threshold seen from two ends. Argue for or against this claim, with specifics. What is the single underlying move, and what does treating them as one idea let you transfer from code review to postmortems (and back)?
D3. Translate for three audiences. The same event—"we changed the default time zone from system-local back to UTC after it caused an incident"—needs to appear in three documents for three readers. Write the one-to-two-sentence version for each, and then name (in one sentence) what makes them different even though the fact is identical (connect to theme 2): - (a) the release notes, for users of the library; - (b) the postmortem, for the team and the future (just the root-cause-relevant line + one action item); - (c) the PR description's "Why," for the reviewer of the fix.
D4. The "how to test" gap. The chapter calls "how to test" the most-skipped and most-valuable part of a PR description. (a) Explain mechanically why a reviewer who can verify a change catches a different (and more dangerous) class of bug than one who can only read it. (b) Connect this to Chapter 25's "every example must be runnable"—what's the shared principle?
D5. When is the writing worth it? Sort these five changes by how much surrounding writing each warrants (from "one-line PR title, nothing else" to "design doc + acceptance criteria + careful PR + likely a postmortem if it goes wrong"), and justify the ordering with the chapter's audience-and-stakes principle: (i) fixing a typo in a log message; (ii) renaming an internal variable; (iii) adding a new public API endpoint; (iv) changing how user passwords are hashed; (v) bumping a dependency's patch version.
Part M — Mixed Practice (Interleaved) ⭐⭐–⭐⭐⭐
These problems mix this chapter with earlier ones. Part of the skill is choosing the right approach—identify which chapter's principle each draws on.
M1. (Ch 34 + Ch 24) A PR description's "Why" section and a code comment in the same change both explain the rationale for a workaround. A teammate asks, "Isn't that redundant?" Answer: what's the difference in audience and lifespan between the why in a PR description and the why in a code comment, and why do you often want both? (Hint: who reads each, and when?)
M2. (Ch 34 + Ch 21) Take Chapter 21's incident-report structure (summary / timeline / root cause / impact / corrective actions) and a postmortem from this chapter. List what they share and the one thing §34.6 elevates above Chapter 21's treatment. Then explain why the workplace incident report was a deliberate "seed" the book planted for this chapter.
M3. (Ch 34 + Ch 25) A bug report for an API integration says: "Your API returns an error and I don't know why." Using Chapter 25's standard for API error documentation and this chapter's standard for bug reports, identify whose failure this likely is (the API's docs, the reporter's report, or both) and what each side should add.
M4. (Ch 34 + Ch 33) Chapter 33 taught requirements language ("the system SHALL…"). This chapter taught acceptance criteria (Given-When-Then). Take this requirement and rewrite it as a testable acceptance criterion, and explain the relationship between a "SHALL" requirement and an acceptance criterion: "The system SHALL validate uploaded files."
M5. (Ch 34 + Ch 2) A senior engineer leaves the comment "obviously wrong, see the docs" on a junior's PR. Using Chapter 2 (audience, the curse of knowledge) and this chapter, explain what's happening in the reviewer's head and why "obviously" is a tell. Rewrite the comment.
M6. (Ch 34 + Ch 12) You've drafted a postmortem. Apply Chapter 12's editing hierarchy (content → structure → paragraphs → sentences → words → proofreading) to it. For each level, name one specific thing you'd check in a postmortem at that level. (E.g., at the content level: does the root cause target the system, not a person?)
Part E — Extension ⭐⭐⭐⭐ (optional; for the Deep Dive track)
E1. The Google code-review angle. Read (briefly) Google's public engineering-practices guide on code review—both "how to do a code review" and "the CL author's guide." Write a 150–200-word summary of two specific practices it recommends that this chapter didn't cover in depth, and one place where its guidance and this chapter's agree exactly. (This is good practice for adopting a team's established conventions, the §34.8 "Going Deeper" point.)
E2. The postmortem-culture tradition. Research the blameless-postmortem tradition associated with site-reliability engineering at large-scale operators. Write a short piece (200–300 words) on why organizations operating at massive scale arrived at blamelessness as a hard norm—what specifically breaks at scale if postmortems assign blame, and what the tradition does structurally to keep them blameless (e.g., templates, review processes, the explicit separation of "what" from "why"). Connect it to this chapter's claim that blamelessness is mechanically necessary, not merely kind.
E3. Raj's review culture. chronoparse now has a dozen regular contributors, and Raj notices that two of them write review comments that, while never cruel, are so terse and unlabeled ("change this," "no," "why?") that newer contributors are afraid to submit PRs. Raj wants to write a short review-guidelines doc (a REVIEWING.md) for the project that raises the standard without being preachy. Draft it: 250–400 words, covering specificity, aiming at the code, blocking vs. nit:, genuine questions, and praise—written in the project's voice, as guidance a real contributor would actually read and follow. (You're writing instructions for reviewers—Chapter 22 meets this chapter.)
Selected solutions and rubrics: See
appendices/answers-to-selected.md. For the open-ended production tasks (Part C, B1's reflection, D2/D5), use the self-assessment rubric below.
Self-assessment rubric for produced documents
Score each dimension 0–2 (0 = absent, 1 = present but weak, 2 = strong).
For a code-review comment (B1, B7, C1):
- Specific: Names the exact line, input, and behavior—not "this is wrong"?
- Aimed at the code: Describes what the code does, never what the author failed to do?
- Path forward: Suggests a fix, a pattern, or an offer to pair?
- Weight labeled: Clearly blocking vs. nit: so the author can prioritize?
- Tone: Candor without cruelty—would the author feel helped, not attacked?
For a PR description (B3, C2): - What: A one- or two-sentence headline graspable before reading the diff? - Why: The intent/reasoning the diff can't show, with the issue linked? - How to test: An exact, runnable way for the reviewer to verify (not just inspect)? - Proportion: Effort matched to the size of the change?
For a bug report (B2, C3): - Reproducible: Steps or a minimal snippet a stranger could run to see the bug? - Expected vs. actual: Both halves, stated concretely (the exact wrong output)? - Environment + evidence: Version, runtime, OS; full error/trace, not a paraphrase? - Actionable, not emotional: Facts a fixer can use, not "broken, ASAP"?
For acceptance criteria (B5, C4): - Testable: Each is a checkable pass/fail condition (Given-When-Then), no "works well"? - Edge cases: Covers empty/no-results, errors, and a concrete limit/performance number? - Buildable: Could a developer build to these without guessing?
For a postmortem (B4, C5): - Blameless: Root cause targets the system ("why was it possible?"), not a person? - Action items: Each changes the system and has an owner and a date—never "be more careful"? - Facts vs. analysis: A neutral timeline kept separate from the root-cause discussion? - What went well: Captures what to keep, not only what to fix?
A piece scoring 2 on every dimension is portfolio-ready. Any 0 is a gap to fix before you'd ship it—and for the review comment and the postmortem, a 0 on "aimed at the code/system" is the failure this chapter exists to prevent.