Most documentation is written in the order the author learned things and read in the order the reader needs them. Those orders are rarely the same, and that gap is why accurate, carefully written pages still go unread. The reader arrives from a search box in the middle of a task, gives the page a few seconds to prove it has the answer, scans for the part that matches their problem and leaves the moment they have it, or the moment they decide it is not there.

This guide is about the craft of writing a single page that survives that kind of reading. The organisational side (ownership, docs-as-code, freshness checks) is covered in the documentation culture guide. Here we work at page level: defining the reader and their task, structuring for scanning, writing sentences and examples that hold up, editing in passes, automating the mechanical checks, testing with real readers and measuring whether any of it worked.

Advertisement

How readers actually use a page

Start from how people actually behave, because every rule later follows from it. Readers of technical docs are almost never reading for pleasure. They have a goal: install the thing, fix the error, find the flag. Eye-tracking research on web pages, most famously the Nielsen Norman Group studies, found that people scan in patterns that favour the start of the page, the start of each section and the first words of each line. The exact pattern varies; the constant is that the middle of long paragraphs is read least.

So model the page as a series of filters, shown in the diagram. A title that does not match the reader's words loses them at the search result. A first paragraph that opens with project history loses them before the content starts. Headings named after nouns ("Configuration", "Overview") instead of tasks make the scan fail. An example that does not run sends them back to search and teaches them to distrust the rest of your docs.

Search resulttitle + snippetFirst paragraphis this my page?Headings scanwhere is my step?Step or examplecopy, runTask donereader leavesLost herevague titleLost herehistory firstLost herenoun headingsLost herebroken exampleFix the earliest leaking stage first; it caps every stage after it
How a reader moves through a documentation page, and where each common writing mistake loses them.

Start from the reader and the task

Before writing a sentence, write a reader card: three lines that say who arrives, what they are trying to do and what they already know. It takes two minutes and settles most later arguments about what to include.

Reader:   backend engineer on another team, first time using our queue
Task:     publish a message from their service and confirm it arrived
Knows:    HTTP, JSON, our deploy tooling; not our auth model or retry rules
Success:  message visible in the consumer within 15 minutes of starting

The card drives three decisions. Scope: anything that does not serve the task moves to another page and gets a link. Assumed knowledge: you can skip HTTP basics, but you must explain your auth model. Type: this reader needs a how-to guide, not a reference table or an architecture essay. The four-type split (tutorial, how-to, reference, explanation, from the Diataxis framework) is described in the culture guide; the page-level rule is one page, one type, one task. A page that tries to teach, instruct and explain at once serves none of those readers, because each one has to dig past material meant for someone else.

Advertisement

Structure for scanning

  • Title in the reader's words. Use the phrase they would type: "Publish a message to the orders queue", not "Messaging Subsystem". Check the search logs of your docs site or wiki for the actual terms.
  • First paragraph as a contract. Within two or three sentences, say what the page lets you do, who it is for and what you need first. A reader should be able to decide to leave without scrolling.
  • Prerequisites as a checklist. Access, versions and tools listed before step one, not discovered at step six.
  • Task headings. Headings are the table of contents a scanner reads. Use verbs ("Rotate the key") or the question being answered ("Why does publish return 409?").
  • Numbered steps, one action each. Each step starts with the action, then gives the command, then the expected result. A step with three actions hides two of them.
  • Tables for comparisons, lists for parallel items, prose for reasoning. Do not force an argument into bullets or a matrix into paragraphs.
  • The answer first, the detail after. State the rule, then the exceptions; state the command, then what the flags mean.

Sentences that survive skimming

Scanners read the first few words of each sentence and paragraph, so put the information-carrying words there. A handful of rules cover most of the gain:

RuleBeforeAfter
Lead with the condition or actionThe service will reject the request with a 409 if the idempotency key has already been used.If the idempotency key was already used, publish returns 409.
Use the imperative for stepsYou will want to make sure that the token has been exported.Export the token.
Name the thing, not "it"It must be set before it starts.Set QUEUE_URL before starting the worker.
Cut hedges and fillerSimply run the following command, which should easily do the job.Run:
One idea per sentenceMessages are batched, compressed, and retried with backoff unless disabled, in which case ordering is lost.Messages are batched and compressed. Failed batches are retried with backoff. If you disable retries, ordering is not guaranteed.

Two more habits matter. Be consistent with terms: if the thing is called a topic in the API, never call it a channel or a stream on the same page, because readers assume different words mean different things. And spell out numbers and limits exactly ("messages up to 256 KB"), because a vague limit means a reader learns it from an error in production.

Examples people can trust

Examples are the part of a page people actually copy, and they are where trust is won or lost. A good example is complete (it runs as pasted, including imports and environment variables), minimal (nothing unrelated to the task), realistic (plausible names and values, not foo) and shows its expected output so the reader can check they succeeded. Mark placeholders unmistakably, such as YOUR_PROJECT_ID, and say where to get each value.

Examples rot faster than prose because the code under them changes. The fix is to execute them. The script below extracts shell blocks marked as tested from Markdown, runs them in a scratch directory, and compares output with the block that follows. Run it in CI on every change to the docs and to the product.

#!/usr/bin/env python3
# doctest_md.py: run ```sh test blocks; compare with the next ```text block
import re, subprocess, sys, tempfile, pathlib

BLOCK = re.compile(r"```sh test\n(.*?)```\s*```text\n(.*?)```", re.S)

def check(path):
    failures = 0
    for i, (cmd, expected) in enumerate(BLOCK.findall(pathlib.Path(path).read_text())):
        with tempfile.TemporaryDirectory() as tmp:
            out = subprocess.run(["bash", "-euo", "pipefail", "-c", cmd], cwd=tmp,
                                 capture_output=True, text=True, timeout=120)
        got = out.stdout.strip()
        if out.returncode != 0 or got != expected.strip():
            failures += 1
            print(f"{path} block {i}: exit {out.returncode}\n--- expected\n{expected}--- got\n{got}\n{out.stderr}")
    return failures

sys.exit(1 if sum(check(p) for p in sys.argv[1:]) else 0)

Exact output matching is brittle for timestamps and IDs, so keep tested examples deterministic or normalise the variable parts before comparing. Untestable examples, such as those needing production credentials, should say so and carry a "last verified" date.

Worked example: rewriting a service page

Here is a typical internal page, condensed. Title: "Queue Service". It opens with two paragraphs on why the team built its own queue in 2021, then a section called "Architecture", then "Configuration" listing fourteen environment variables, then "Usage" with a code snippet that imports a module renamed last year. Authentication is mentioned in a sentence inside Configuration. The page is accurate in most places and nobody can publish a message by following it.

Apply the reader card from earlier. The rewrite splits the page into three. A how-to titled "Publish a message to the queue" opens with: "Send a message from your service to any queue topic in about 15 minutes. You need a service account and network access to the queue gateway." A prerequisites checklist follows, then five numbered steps (request credentials, install the client, set two variables, publish, confirm in the consumer), each with a tested command and its expected output. A short "If it fails" section maps the three common errors (401, 409, 413) to fixes. The fourteen-variable table moves to a reference page linked from step three, and the history and architecture move to an explanation page linked at the end.

The how-to went from about 1,900 words to about 700. Nothing true was deleted; it moved to the page whose reader wanted it. That is the usual result. Most bad pages are not too long. They are several pages stacked on top of each other.

Edit in passes

Edit in separate passes, each looking for one kind of problem. Trying to fix structure and commas at once means you fix the commas and miss the structure.

  1. Structure pass. Read only the title, first paragraph and headings. Do they tell the reader card's story? Is anything off-task?
  2. Accuracy pass. Follow the page literally on a clean machine or account. Every command, every value, every screenshot.
  3. Cut pass. Remove anything the reader does not need for the task. Aim to remove a fifth of the words; most first drafts can lose that without losing a fact.
  4. Sentence pass. Apply the sentence rules: conditions first, imperatives, consistent terms, no hedges.
  5. Mechanical pass. Links, spelling, code formatting, product names. Automate this one.

Automate the mechanical checks

Vale is an open-source prose linter that runs rules written in YAML against Markdown, reStructuredText, AsciiDoc and other formats, and fits in CI next to the doctest above. A minimal setup is a config file and one style folder:

# .vale.ini
StylesPath = styles
MinAlertLevel = suggestion

[*.md]
BasedOnStyles = Vale, Docs

# styles/Docs/Hedging.yml
extends: existence
message: "Remove '%s'; say what happens instead."
level: warning
ignorecase: true
tokens:
  - simply
  - just
  - easily
  - obviously
  - of course

# styles/Docs/Terms.yml
extends: substitution
message: "Use '%s' instead of '%s'."
level: error
swap:
  channel: topic
  login to: log in to

Keep the rule set small and agreed. A linter that flags forty things per page gets disabled within a month. Start with your product's terminology, hedge words and banned phrases, and add rules only when a reviewer has made the same comment three times. Pair it with a link checker so moved pages do not become dead ends.

Test with real readers

Authors cannot test their own pages: they already know the missing step, so they never notice it is missing. The cheapest reliable test is a task-based session with someone who matches the reader card. Give them the task, not the page ("publish a message to the orders queue"), let them find the page the way a real reader would, and watch without helping. Note every pause, every re-read and every time they leave the page. Usability practitioners have long found that a handful of sessions, often around five, surfaces most of the serious problems. Run three, fix, run three more.

Between sessions, a lighter test still helps: ask a colleague to read only the title, first paragraph and headings for thirty seconds, then tell you what the page does and where step four is. If they cannot, the structure pass failed.

Measure whether it works

SignalWhat it tells youCaveat
Docs search queries with no result or no clickMissing pages and wrong titlesNeeds search logging on the docs site
Support tickets and chat questions linking or re-asking a pageWhere the page fails readersRequires tagging tickets by doc topic
Task completion in usability sessionsWhether the page works end to endSmall samples; directional
"Was this helpful?" with a free-text boxSpecific complaintsLow response rate, skews negative; read the text, ignore the ratio
Time on pageVery little aloneA fast visit can be success or abandonment

Pick one or two signals tied to a goal, such as "cut 'how do I publish' questions in the platform channel by half this quarter", and review them monthly. Page views tell you what is popular, not what is useful.

Failure modes and trade-offs

  • Writing for yourself. The page skips the step that is obvious to its author. Fix with the reader card and a usability session.
  • Everything page. Tutorial, reference and history in one scroll. Split by type and link.
  • Untested examples. One broken snippet costs the reader's trust in every page. Execute examples in CI.
  • Screenshots as instructions. They go stale silently and cannot be searched or copied. Use them to confirm, not to instruct.
  • Over-linting. Rules nobody agreed to teach writers to ignore all rules.
  • Trade-off: completeness against findability. Every caveat you add makes the main path harder to see. Put edge cases in a clearly labelled section after the steps, or on the reference page.

What to do next

  1. Pick the five most visited pages in your docs and write a reader card for each.
  2. Rename titles and headings to the reader's search terms and task verbs.
  3. Rewrite each first paragraph as a contract: what, for whom, what you need first.
  4. Split any page that mixes tutorial, how-to, reference and explanation.
  5. Mark runnable examples and run them in CI with a doctest script.
  6. Add Vale with a small agreed rule set: terminology, hedges, banned phrases.
  7. Run three task-based sessions with readers who match the card; fix and repeat.
  8. Choose one outcome metric, such as repeated support questions, and review it monthly. For runbooks and design docs, apply the same method using the runbook guide and design doc guide; for messages users see, see writing error messages.
Key takeaway: Readers arrive mid-task, scan and leave, so write for that behaviour. Define the reader and task before writing, keep one page to one type and one task, put the answer in the title, first paragraph and headings, and lead sentences with the condition or action. Make examples complete and run them in CI, edit in separate passes, lint the mechanical rules, and test with real readers instead of trusting your own reading.