Exercises — Chapter 25: README Files, API Documentation, and Developer-Facing Writing
Writing is learned by writing. These exercises ask you to produce and revise real developer-facing documents—READMEs, API references, ADRs, changelogs—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 developer-facing writing. Name what works and what's broken, in the chapter's terms.
A1. A README opens like this:
# fastcache
In modern distributed systems, caching is essential to performance, and the
tradeoffs between consistency, latency, and memory footprint are subtle and
deeply context-dependent. fastcache emerged from years of experience operating
high-throughput services and embodies a particular philosophy about cache
invalidation, which as the saying goes is one of the two hard problems in
computer science...
The first install command appears at the very bottom, after 600 words. What's the core failure here, and what's the one change that would help most?
A2. An API endpoint is documented as:
### GET /orders/{id}
Retrieves an order. Returns the order data.
List at least four specific pieces of information a developer needs that this is missing.
A3. Here is a "changelog" entry. Identify everything wrong with it as a changelog (as opposed to a commit log):
## v3.0.0
- merge branch feature/refactor
- fix
- update readme
- remove old API
- bump
A4. Two READMEs for similar tools. README X leads with a one-line description, a five-bullet feature list, an install command, and a three-line runnable example. README Y leads with a logo, twelve badges, a "Table of Contents" with nineteen entries, a "Motivation" section, a "Background" section, and a "Philosophy" section—the install command is under heading 14. Both projects are equally good code. Which README will get more users, and state the principle in one sentence.
A5. An ADR contains a "Context" section and a "Decision" section but no "Consequences" section. Why is the missing section the one that most undermines the ADR's future value?
A6. A curl example in an API doc reads:
curl https://api.example.com/search?q=hello
The actual API requires an Authorization: Bearer header and the endpoint is /v2/search, not /search. What's the damage when a reader copies and runs this, and what principle did the author violate?
A7. A contributing guide says: "We welcome contributions! Please make sure your code is high quality and follows our conventions before submitting." A new contributor reads this and is no closer to contributing. Why? What would actually help?
A8. Compare these two feature-list bullets for the same library: - (a) "Blazingly fast, highly flexible, enterprise-grade parsing engine" - (b) "Parses 50 MB log files in under 200 ms; pluggable format definitions"
Which carries information, which carries none, and why (name the Chapter 7 concept)?
Part B — Revise This ⭐⭐
Rewrite the following weak developer-facing writing. You're given the scenario and the flawed text; produce the improved version.
B1. The motivation wall. Rewrite the opening of a README whose current first paragraph is:
"The problem of configuration management has plagued software teams for decades. As systems grow in complexity, the number of configuration parameters explodes, and keeping them consistent across environments becomes a nightmare of copy-paste errors and drift. confdeck was created to solve this problem by providing a unified, declarative approach to configuration that scales from a single service to a fleet of microservices."
The tool, confdeck, loads and validates config files from YAML and environment variables. Write a proper README top section: one-line description, a 3–4 bullet feature list, and an installation block (assume pip install confdeck, Python 3.9+). Move or cut the philosophy.
B2. The prose-only usage. A README describes usage like this:
"To use confdeck, you instantiate a Config object, optionally passing it the path to your config file, and then access your configuration values as attributes on that object. If a value is missing or fails validation, an exception is raised."
Rewrite this as a runnable quick-start example (invent plausible but realistic syntax), showing the call and the result, ending with a one-line pointer to fuller docs.
B3. The happy-path-only endpoint. Expand this endpoint into a complete reference (request table, response with status code, errors table, runnable example). Invent realistic details.
### POST /payments
Charges a payment. Send the amount and card token.
B4. The decision with no record. A team chose to store user sessions in Redis rather than in the primary Postgres database. The reasoning (from a meeting): Postgres session writes were causing lock contention under load; Redis is in-memory and far faster for the read-heavy session pattern; the trade-off is that sessions don't survive a Redis restart unless persistence is configured, and it's another piece of infrastructure to operate. Write this as a complete ADR (Status, Context, Decision, Consequences).
B5. The commit-log changelog. Convert this raw commit dump into a proper user-facing changelog entry for version 1.4.0, grouped by change type, leading with breaking changes, with a migration path:
- add --json output flag
- internal refactor of the renderer
- fix crash when input file is empty
- rename --output to --out (old flag removed)
- speed up rendering for large files
- fix typo in help text
B6. The barren contributing note. A project's entire contributing documentation is one line in the README: "PRs welcome." Write a real CONTRIBUTING.md for a Python CLI tool. Include setup (clone + install), how to run tests (pytest), code style (assume black and ruff), and a numbered submission process. Invent reasonable specifics.
B7. The badge-spam header. A README's top has fourteen badges (build, coverage, version, downloads/month, downloads/week, downloads/total, stars, forks, contributors, last-commit, issues, PRs, Twitter, Discord). Decide which 3–4 badges actually carry decision-relevant information for a new user, and justify each keep/cut in a phrase.
B8. The undocumented errors. An endpoint documents a 200 response but no failures. The endpoint is POST /login (takes email and password). Write the Errors section only: list the realistic failure responses (status code, stable error code, plain-language meaning) a developer integrating a login flow must handle.
Part C — Write This ⭐⭐–⭐⭐⭐
Each scenario asks you to produce a complete document or section from scratch.
C1. Fix this bad README (the centerpiece task). Here is a real-looking neglected README for a fictional open-source library, slugify-pro, which converts arbitrary text into URL-safe slugs ("Hello, World!" → "hello-world"). Rewrite it completely into an excellent README using this chapter's structure.
# slugify-pro
Slugification is the process of converting a string into a "slug" — a version
of the string that is safe to use in a URL, typically lowercase, with spaces
replaced by hyphens and special characters removed or transliterated. This is
harder than it looks once you account for Unicode, accented characters, emoji,
multiple languages, and the various edge cases around leading/trailing
separators and consecutive separators. slugify-pro handles all of this with a
configurable pipeline. It supports custom replacement rules, length truncation,
and pluggable transliteration backends. It has been used in production by
several companies. Internally it uses a multi-stage normalization process.
Performance is good. It is available on the package registry. Contributions are
welcome but please discuss first. Licensed under Apache 2.0.
Your rewrite must include: a one-line description, a feature list, an installation section (invent: npm install slugify-pro), a quick-start with a runnable example showing input and output, a Documentation/links section, a Contributing section, and a License line. Aim for something a stranger could use in two minutes.
C2. Document this API endpoint. Design and fully document a single endpoint for a fictional URL-shortener API: POST /links, which takes a long URL and an optional custom alias and returns a short URL. Produce a complete reference: a one-line description, a request table (fields, types, required, constraints), a request body example, a response (with status code and body), an errors table (at least three realistic failures with status + stable code + meaning), and a runnable curl example with auth. Match the §25.4 standard.
C3. Write an ADR. Pick a real decision from a project you've worked on (or invent a realistic one), and write a complete ADR for it. Good candidates: choosing a framework or library over an alternative, choosing a data format (JSON vs. protobuf), choosing a database, choosing to build vs. buy, choosing a particular architectural pattern. Include Status, Context (the forcing problem and the alternatives weighed), Decision, and Consequences (positive and negative—be honest about the costs). One page maximum.
C4. Write a quick-start that converts. For any tool, library, or script you actually use or have written, write only the quick-start section: the shortest path from "installed" to "a working result the reader can see." One runnable example, showing the output. Constraint: a reader who copies your example must get a real result with at most one obvious edit. Then describe (in 2–3 sentences) how you'd run the clean-machine test on it.
C5. Write a changelog entry for a breaking release. You're releasing version 2.0.0 of a library. The release: adds async support, drops Python 3.7, renames the main run() function to execute() (old name removed), fixes a memory leak, and changes the default timeout from 30s to 10s. Write the changelog entry, grouped properly, leading with breaking changes, with migration paths for every breaking change.
Part D — Synthesis & Critical Thinking ⭐⭐⭐
D1. Find the flaw. A developer argues: "ADRs are a waste of time—if you write good, clean code with clear names, the design is self-documenting and you don't need a separate document explaining your decisions." Using this chapter and Chapter 24, explain precisely what this argument gets wrong. (Hint: distinguish what code can show from what it cannot.)
D2. Translate for three audiences. The same change—"we switched the session store from Postgres to Redis"—needs to appear in three documents for three readers. Write the one-to-two-sentence version for each: - (a) the changelog, for a user of the library who is upgrading; - (b) the ADR, for a future maintainer (just the Decision line + the key Context); - (c) a commit message, for the developers of the project.
Then state, in one sentence, what makes the three different even though the underlying fact is identical (connect to theme 2).
D3. The README that's all reference, the reference that's all tutorial. Chapter 26 will name this with Diátaxis, but you can diagnose it now. (a) Describe what goes wrong when an API reference is written as a long narrative tutorial ("First, let's create a user. Now that we have a user, let's…"). (b) Describe what goes wrong when a README quick-start tries to be an exhaustive reference (every option, every edge case). State the underlying principle both violate.
D4. The drift problem. Documentation that was correct once and is now subtly wrong is, the chapter argues, worse than no documentation. (a) Explain why "wrong docs are worse than no docs." (b) Propose three concrete defenses against doc drift, drawing on the chapter, and explain which one is strongest and why.
D5. Apply the threshold. The chapter's threshold concept is "documentation is the product's user interface for developers." Take a project you know (yours or a popular open-source one) and argue, with specifics, how treating its docs as UI rather than as an afterthought would change what gets documented and in what order. What would move to the top? What would move out of the doorway entirely?
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 25 + Ch 24) A function in your library has both a docstring (Chapter 24) and an entry in your API reference (Chapter 25). A reader asks, "Why document it twice—isn't that redundant and a drift risk?" Answer the question: what's the relationship between a docstring and API reference docs, and how do good teams keep them from drifting apart? (Hint: generated docs.)
M2. (Ch 25 + Ch 22) Take a README's installation + quick-start section and evaluate it the way Chapter 22 says to evaluate instructions: as a procedure a doer follows on a real machine. Pick any README (yours or a real one), list the exact steps it implies, and identify where a "clean machine" would stall (an assumed dependency, an undocumented environment variable, a step the author does automatically). You're applying Chapter 22's beginner test to Chapter 25's front door.
M3. (Ch 25 + Ch 7) A README's feature list reads: "Powerful, intuitive, lightning-fast, enterprise-ready, developer-friendly." Rewrite it into concrete, information-carrying bullets (invent plausible specifics for a hypothetical HTTP client library). Name the Chapter 7 concept that the original violates and the diagnostic you applied.
M4. (Ch 25 + Ch 4) A long API reference has nineteen endpoints under flat, form-named sections ("Section 1," "Section 2," …) with no grouping and no informative headers. Using Chapter 4's structure principles, propose how you'd reorganize it so a developer can find the endpoint they need fast. (Consider grouping by resource, informative headers, and a top-level index.)
M5. (Ch 25 + Ch 3) Here is a verbose endpoint description. Cut it to a clear one-liner without losing the necessary information, applying Chapter 3's conciseness discipline:
"This particular endpoint is designed to provide the functionality of allowing the client to perform the action of retrieving a comprehensive listing of all of the user accounts that are currently present within the system at the time of the request."
M6. (Ch 25 + Ch 12) You've drafted a complete README. 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 README at that level. (E.g., at the structure level: is the quick-start above the philosophy?)
Part E — Extension ⭐⭐⭐⭐ (optional; for the Deep Dive track)
E1. The OpenAPI angle. Research (briefly) what an OpenAPI/Swagger specification is and how generating API documentation from a machine-readable spec addresses the drift problem this chapter raises. Write a short paragraph (150–200 words) explaining the trade-off: what you gain (docs that can't drift from the code, an interactive "try it" console) and what you still have to write by hand (the why, the conceptual overview, the getting-started narrative that a generated reference can't produce).
E2. The full documentation audit. Choose a real open-source project (one you use, ideally). Audit its documentation against the open-source documentation standard from §25.7: Does it have a README with install + runnable quick-start? API/reference docs with documented errors? ADRs or any record of design decisions? A changelog with migration paths? A CONTRIBUTING.md? Write a one-page audit: what meets the standard, what's missing, and the single highest-impact improvement you'd recommend, with your reasoning. (This is also good practice for the kind of constructive documentation review you'll do on real teams.)
E3. Raj's next problem. Raj fixed chronoparse's README and the "how do I install this?" issues stopped. Three months later, a new class of issue appears: developers using the library are filing bugs that are really questions—"why does parse('tomorrow') return midnight and not the current time?"—because the behavior is documented as reference but never explained. Diagnose this in the chapter's terms (and preview Chapter 26): which kind of documentation is missing, and what would Raj write to address it? (Hint: this is the gap between reference and explanation.)
Selected solutions and rubrics: See
appendices/answers-to-selected.md. For the open-ended production tasks (Part C, and D2/D5), use the self-assessment rubric below.
Self-assessment rubric for produced documents (Part C)
Score each dimension 0–2 (0 = absent, 1 = present but weak, 2 = strong).
For a README (C1, C4): - Time-to-first-success: Is there an install command and a runnable example a stranger could use in under five minutes? (The single most important dimension.) - Order: Does it lead with what-it-is and the quick-start, with philosophy moved down or out? - Runnable example: Does the example show the call and the result, copy-pasteable, and would it actually run? - Scannability: Do informative headers (Features, Installation, Quick start, …) let a reader jump to their question (Chapter 4)? - Completeness without bloat: Feature list, contributing pointer, license—present but brief?
For an API endpoint (C2): - The five parts: purpose, request (typed, required-marked), response (with status code), errors (status + stable code + meaning), runnable example—all present? - Errors documented: Is the failure path covered, not just the happy path? (The most-skipped, most-needed part.) - Source-independence: Could a developer use it without reading your code? If not, what's the gap? - Realism: Are the request/response bodies actual JSON with plausible values, not prose schemas?
For an ADR (C3): - The why: Does Context name the forcing problem and the alternatives weighed? - Honesty: Does Consequences include the negative trade-offs accepted, not just benefits? - Scope: One decision, one page? - Future-usefulness: Would this stop a future contributor from blindly undoing the decision?
For a changelog (C5): - Audience: Written for the upgrading user, not as a commit dump? - Grouping + lead: Grouped by change type, leading with breaking changes? - Migration: Does every breaking change include a migration path?
A piece scoring 2 on every dimension is portfolio-ready. Any 0 is a gap to fix before you'd ship it.