Technical Writing and Documentation Questions
The craft of producing durable, reference-quality written artifacts and keeping them accurate: READMEs and quick-start guides, design docs, RFCs and technical proposals, runbooks and deployment guides, model cards, datasheets and data dictionaries, bug reports and reproducible examples, postmortem write-ups, handoff documents, pull request descriptions, code comments, release notes, experiment reports, and knowledge-base articles. Covers structure and information design, writing for a specific audience and for future readers (including plain language and accessibility), templates and style standards, docs-as-code workflows with CI checks, testing of examples and snippets, documentation review and quality checks, versioning and freshness checks on the documents you own, keeping sensitive data out of docs, and measuring whether documentation works. Architecture decision records, API reference docs, PRDs and PR/FAQs, and live presentations are covered elsewhere.
What rules of thumb do you follow for clear technical writing aimed at engineers, product managers and lawyers at once? Show one rule applied to a sentence you would actually write.
Sample Answer
Direct answer
Write one document that works for three readers by leading with the conclusion, using one word for one thing, and making every sentence concrete: a named actor, a number, a unit. Engineers want checkable claims, product managers want the decision and its impact, and lawyers want commitments that cannot be read two ways. Plain, exact sentences serve all three.
Rules of thumb
- Put the conclusion first. The first two sentences say what happened, what is decided, or what is asked. Detail follows for those who need it.
- One term, one meaning. Define a term once, then never swap in a synonym. If "customer" means the paying company, do not later use "user" for the same thing. Lawyers read a change of word as a change of meaning.
- Name the actor and use active voice. "The service deletes the file" says who does what. "The file will be deleted" hides who.
- Use numbers, units and dates, not adjectives. "Fast", "soon" and "a short period" cannot be checked.
- One idea per sentence, and short. It survives translation and skimming.
- Separate facts, opinions and commitments. Label recommendations as recommendations. Use "must" for a requirement, "should" for a recommendation and "may" for a permission, the convention of RFC 2119 (an internet standard whose keywords are MUST, SHOULD and MAY, written in capitals in the standard itself). Avoid "can" for permission, since it can also mean ability.
- Say what you do not know. "We have not tested above 500 requests per second" is more trustworthy than silence.
- Expand acronyms on first use and keep a glossary.
One rule applied to a real sentence (rule 3 plus rule 4)
Before:
Customer data may be retained for a period following termination as deemed appropriate and will be handled in accordance with policy.
After (example figures, to be confirmed with the owner):
We delete customer data 30 days after the contract ends. We delete backups within 90 days after that.
What changed and why each reader benefits:
| Reader | Before | After |
|---|---|---|
| Engineer | Cannot build or test "a period" | A checkable deletion job with two deadlines |
| Product manager | Cannot tell customers anything | Can quote the retention promise |
| Lawyer | "May" and "as deemed appropriate" are vague, so risk is hidden | The commitment is explicit and reviewable |
Trade-offs and pitfalls
- Precision creates commitments. "We delete" is a promise, so do not publish a number until the owning team and legal have confirmed it. If the true answer is "it depends", write the dependency: "We delete data 30 days after the contract ends unless a legal hold applies."
- Do not hide behind qualifiers to stay safe ("generally", "in most cases"). Either state the exception or drop the hedge.
- Layer the document: a short summary on top for the PM and the lawyer, detail below for the engineer, rather than three separate versions that drift apart.
- Have a person from each group read the draft for one thing only: the sentence they would act on. Their confusion shows where the text is weak.
A client reports inconsistent and translated guides across regions, and misconfigurations followed in production. How do you harmonise the documentation and make it translation-ready?
Sample Answer
Direct answer
Two separate failures are hiding here. The regional guides drifted because there is no single source, and the misconfigurations happened because translation touched things that must never change (config keys, commands, values). I would fix both: make one canonical source, mark which parts are translatable and which are literal, translate through a controlled process, and add a check that catches altered code in any language. I would start with the install and configuration pages, since those caused production harm.
1. One source of truth
- Keep a single canonical language (say English). Regional guides are translations of it, plus small region overlays for facts that truly differ (endpoints, data-residency notes; data residency means rules about which country or region data must be stored in), kept as structured data rather than as copied prose.
- Each translated page records
source_commitin its front matter (the header block at the top of a page). If the source moves past that commit, CI (continuous integration, the automatic checks run on every proposed change) marks the page stale and shows a banner: "This translation is behind the English version." Readers then know when not to trust it.
2. Make the source translation-ready
- Short sentences, one term per concept, a glossary (termbase: an approved list of terms and their required translations) that translators must follow. No idioms or jokes, no sentence fragments glued together in code, no text inside screenshots (use text labels or alt text).
- Say units and formats explicitly, and let locale settings (the regional formatting rules for dates and numbers) render them.
- Never translate literals: code blocks, commands, flags, config keys, values, file paths, UI labels quoted exactly as they appear. Mark them so translation tools skip them.
3. Controlled translation
Use a translation memory (a database of past translated segments that is reused so wording stays consistent), machine translation for a first pass, and a human reviewer for high-risk pages (install, security, configuration). Tier languages (rank them into groups) by user base: fully reviewed for the largest, machine-translated with a visible label for the rest.
4. The check that would have prevented the incident
import re
FENCE = re.compile(r"```[a-z]*\n(.*?)```", re.S)
def code_blocks(markdown):
return FENCE.findall(markdown)
def compare(source, translation):
problems = []
src, tr = code_blocks(source), code_blocks(translation)
if len(src) != len(tr):
problems.append(f"block count differs: {len(src)} vs {len(tr)}")
for i, (a, b) in enumerate(zip(src, tr), start=1):
if a != b:
problems.append(f"code block {i} was altered in translation")
return problems
english = "Set the region:\n```yaml\nregion: eu-west\nretries: 3\n```\nThen restart.\n"
spanish = "Configure la region:\n```yaml\nregion: eu-west\nreintentos: 3\n```\nLuego reinicie.\n"
for problem in compare(english, spanish):
print(problem)
print("checked", len(code_blocks(english)), "block(s)")
It prints code block 1 was altered in translation and checked 1 block(s). How the checker works: FENCE finds text between triple-backtick markers, and re.S lets . match line breaks so a multi-line block is captured whole. zip pairs the Nth English block with the Nth translated block, and enumerate numbers them so the message can say which block changed.
The Spanish page translated the key retries to reintentos. The application would silently ignore an unknown key and fall back to its default, which is exactly how a "followed the guide" misconfiguration reaches production. CI now blocks the merge.
What an overlay looks like
# overlays/eu.yaml (only the facts that differ from the English source)
api_endpoint: https://api.eu.example.com
data_residency_note: Data is stored only in EU data centres.
The page text references these values instead of copying them, so a fix in English reaches every region.
Worked example
A client has US, EU and APAC guides. Week 1: diff each against English, list mismatches, and choose English as canonical. Week 2: add overlays for the three real regional differences and front matter to every page. Week 3: turn on the code-block check and stale banners. Later: add remaining languages by tier.
Trade-offs
- Full human review of every language is expensive. Tiering by risk and user base spends it where errors hurt.
- Machine translation is fast but can alter meaning; label it and never let it touch literals.
- What would change my call: with two regions and a few dozen pages, skip the translation memory and rely on the glossary and the code-block check.
How do you write a deployment guide so a reader can confirm each step worked without asking the author? Give me a concrete example of the evidence you would build into one step.
Sample Answer
Direct answer
A deployment guide is a numbered procedure for putting a change into an environment. Every step should have four parts: the action, the expected observable result, a check the reader runs themselves, and what a failure looks like with the next move. The reader then confirms success from evidence on their own screen instead of trusting the author. The key design choice is to verify the outcome (what is now running), not merely that the command did not error.
Concrete example: one step with its evidence
Illustrative service orders-api on Kubernetes (a system that runs copies of a service, called pods):
STEP 4. Deploy version 1.8.2 to production.
Do:
kubectl -n orders set image deployment/orders-api api=registry.example.com/orders-api:1.8.2
Wait for it (a rollout is Kubernetes replacing the old pods with new ones, a few at a time):
kubectl -n orders rollout status deployment/orders-api --timeout=120s
Expected last line: deployment "orders-api" successfully rolled out
Prove it is the version you wanted (do not skip). The jsonpath expression below just prints the full image reference (registry, name and tag) of the first container in the deployment's pod template, that is, which version Kubernetes has been told to run:
kubectl -n orders get deployment orders-api -o jsonpath='{.spec.template.spec.containers[0].image}'
Expected output: registry.example.com/orders-api:1.8.2
Prove it serves traffic:
curl -fsSi https://orders.example.com/health
Expected: a first line of HTTP/2 200 (or HTTP/1.1 200 OK) and a body containing "status":"ok"
(-i prints the status line and headers; without it curl shows only the body. -f makes curl exit non-zero on a 4xx or 5xx response.)
If the wait ends with "error: timed out waiting for the condition" (the progress lines "Waiting for deployment ... rollout to finish" are printed during every normal rollout, so on their own they are not a failure):
run kubectl -n orders get pods and look for CrashLoopBackOff (a pod status meaning the container keeps starting, crashing and being restarted with growing delays), then go to
"Rollback" at the end of this guide. Do not continue to step 5.
Why this step works
- The second check compares the image the Deployment is now configured to run with the version in the step, which catches "the command succeeded but the wrong version was applied" (a typo or a stale tag). The rollout wait is what proves the old pods were actually replaced; to see what is running right now, read the pods' images with
kubectl -n orders get pods -o jsonpath='{.items[*].spec.containers[*].image}'. - Expected output is written out, so the reader can compare text instead of judging.
- The failure branch tells the reader where to go, so they do not improvise.
- The step is bounded (
--timeout=120s), so "still waiting" becomes a decision, not an endless hang.
Practices that generalise
- Preconditions before step 1: access, tool versions, the approved release number.
- One action per step, and outcome checks placed before the next action.
- Match on stable substrings in expected output, not banners with version numbers that change monthly.
- Make risky steps reversible: each has an undo, or an explicit note that it is irreversible and needs a second person.
- Test the guide: give it to someone who was not involved and do a dry run in staging. Each question they ask is a missing piece of evidence.
Another evidence example. For a database migration step, the check is a query against the migrations table that returns the latest applied migration name, compared with the name in the release notes.
Pitfalls
- "Verify the deployment succeeded" with no method.
- Expected output copied once and then wrong after a tool upgrade.
- Verifying only that a process is up, not that it does the job.
Write a one-page quick-start for engineers adopting a new internal shared component, for instance a feature store. What must a first-time user be able to do in ten minutes, and which pitfalls belong on the page?
Sample Answer
Direct answer
The quick-start's job is one measurable outcome: a first-time user gets real value from the component in ten minutes, without asking anyone. For a feature store (a shared system that keeps precomputed model input values, called features, so training and live serving use the same definitions), that means install, authenticate, read one existing feature, and see it verified. An entity is the thing the features describe (here a customer, identified by an entity id such as customer_id = 1042). Online features are the latest values served quickly for live predictions, as opposed to offline features, which are historical values used to build training data. A namespace is a named folder that keeps sandbox features apart from production ones, and the catalogue is the searchable list of registered features and their owners. The pitfalls on the page are the ones that bite first-time users, not a full reference.
What a first-time user must do in ten minutes
| Minutes | Step | Success check |
|---|---|---|
| 0-2 | Install the client with a pinned version and set the project name | featurestore --version prints a version |
| 2-4 | Authenticate with your own team credentials (never a shared production key) | A test call returns "authenticated as <you>" |
| 4-6 | Read features for one known entity id (for example customer_id = 1042) | You see the feature values and a timestamp |
| 6-9 | Define one new feature in a sandbox namespace and fetch it | The new value appears in the read |
| 9-10 | Find your feature in the catalogue or UI and see who owns it | You can name its owner and freshness |
The steps use an illustrative client, since this is an internal component:
from featurestore import Client # illustrative internal client
client = Client(project="sandbox")
row = client.get_online_features(
features=["customer.orders_30d", "customer.avg_basket"],
entity={"customer_id": 1042},
)
print(row) # expect two values plus the time each was computed
The page states the expected result after each step, so success is visible without guessing. In the code: Client(project="sandbox") connects to the sandbox namespace, get_online_features asks for two named features for one customer, and the print should show one value per feature plus the time each was computed.
Pitfalls that belong on the page
Pitfalls 1 and 2 are the ones that fail silently and cost the most; 3 to 6 are housekeeping the page can state in one line each.
- Point-in-time correctness. When building training data, fetch each feature value as it was at the label's timestamp. Using today's value leaks the future into training, so the model looks better offline than it will in production. Example (illustrative): customer 1042 churned (stopped buying) on 2025-03-15, and the label timestamp is that date. Their
orders_30dwas 5 on 2025-03-15, but by today (2025-06-01) it is 0 because they left. If training uses today's 0, the model learns "zero orders means churn", which looks perfect offline, yet in production the model only ever sees the value 5 before the customer leaves. The correct training value is the one as of 2025-03-15. - Training-serving skew. Reuse the registered definition. Recomputing the feature separately in your own code is how the two sides drift apart.
- Freshness. A feature has a refresh interval and a time-to-live (how long a value stays valid). Say which features are hourly and which daily, so a user does not expect real-time.
- Entity keys. Use the documented key name and type (an id stored as text vs integer silently returns nothing).
- Sandbox vs production. Where to experiment and what needs a review before promotion.
- Cost and quotas. Large backfills (recomputing history) consume shared capacity: ask the owner first.
Worked example
A new engineer reads the page at 10:00. By 10:04 they are authenticated. At 10:06 they see orders_30d = 7 for customer 1042 with a computed-at time. They ask, "is this current?" The page's freshness note says daily at 03:00, so a 10:00 read is 7 hours old, which they can decide is acceptable for their model. They never opened the full reference.
Trade-offs and pitfalls of the page itself
- The page must stay one screen long. Link to the reference, the on-call channel, and the design doc rather than embedding them.
- Test the ten-minute claim by watching someone new do it, then cut every step where they hesitated.
- Put the sharpest pitfall (point-in-time leakage) near the top of the pitfalls list, since it is silent and costly.
- Examples must use the sandbox, so copy-paste never touches production.
A peer reviewer says your design doc is 'too high-level' while a product manager says it 'has too much technical detail.' How do you rewrite the doc and structure communication to satisfy both audiences? Describe your plan and provide examples of two sections: an executive summary and an appendix entry.
Sample Answer
Direct answer
Both reviewers are right about different readers, so the fix is layering, not compromise. I would restructure into a one-page executive summary (decision, value, cost, risk, dates, no internals), a main body at engineering depth, and appendix entries that hold the deep detail. Each reader enters at the right layer and can drill down by link. Then I would confirm with each reviewer what decision they must make from the document.
Plan
- Ask the peer what specifically is missing (failure behaviour? data model?) and the PM which paragraphs they could not use. This turns opinions into a list.
- Move every mechanism-level detail out of the summary and body into named appendix entries, leaving a one-sentence pointer.
- Add to the summary whatever the PM needs to decide: scope, timeline, cost, user impact, risks in plain words, and what we need from them.
- Send the peer the body and appendix, the PM the summary, then hold one short joint review to check both are satisfied.
Example executive summary (illustrative values)
"Proposal: move image resizing out of the web application into a queue-backed worker service. Why: resizing slows page requests during uploads, and a slow upload can block other users. User impact: faster uploads at busy times; no visible interface change. Cost: one new service and queue; about six engineer-weeks (estimate, to be confirmed after spike). Risk: a failed worker could leave an image without thumbnails; mitigated by automatic retries and a nightly repair job. Rollout: shadow mode for two weeks, then 10 percent of uploads, then all. Decision needed from product: accept a two-week delay to the gallery feature."
Example appendix entry
"A3. Retry and duplicate handling. The queue delivers each message at least once, so a resize job may run twice. The worker is idempotent (repeating it has the same effect as running it once): output filename is derived from the source image hash, and a repeat overwrites the same file. Retries use exponential backoff (waiting longer after each failure) up to five attempts, then the message moves to a dead-letter queue (a holding queue for failed messages) that pages the owning team. Alternatives rejected: exactly-once delivery (unavailable in our queue), a dedupe table (extra state to maintain)."
Pitfalls
- Compromising by writing a medium-detail middle that serves nobody.
- Hiding risk in the appendix. Risks the PM must accept belong in the summary, in plain language.
- Numbers in the summary must be labelled estimates, and each traceable to a body section.
Unlock Full Question Bank
Get access to all Technical Writing and Documentation interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.