<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Natália Kováč</title>
    <description>The latest articles on DEV Community by Natália Kováč (@nataliakovac).</description>
    <link>https://dev.to/nataliakovac</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4198867%2F0c856d36-1f97-4a13-ac53-9731d656823f.jpg</url>
      <title>DEV Community: Natália Kováč</title>
      <link>https://dev.to/nataliakovac</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nataliakovac"/>
    <language>en</language>
    <item>
      <title>Editing numbered steps so readers never lose their place</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Fri, 13 Nov 2026 10:54:19 +0000</pubDate>
      <link>https://dev.to/nataliakovac/editing-numbered-steps-so-readers-never-lose-their-place-1f1g</link>
      <guid>https://dev.to/nataliakovac/editing-numbered-steps-so-readers-never-lose-their-place-1f1g</guid>
      <description>&lt;p&gt;Numbered steps look like the easy part of a tutorial. But readers move back and forth between the page and their screen at every step, and that's where they lose their place. A step that hides two actions, or a warning that comes after the click, sends them back to reread.&lt;/p&gt;

&lt;p&gt;When I edit a procedure, I read it as someone with one eye on the page and one on the screen. These are the edits I make most often.&lt;/p&gt;

&lt;h2&gt;
  
  
  One action per step
&lt;/h2&gt;

&lt;p&gt;A step should be one thing the reader does before looking back at the page. When I see "and then" in a step, or two commands, I split it. The list gets longer, but ten short steps are easier to follow than five crowded ones, because the reader always knows which number they're on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Condition first, then the action
&lt;/h2&gt;

&lt;p&gt;"Click &lt;strong&gt;Delete&lt;/strong&gt;, but only if you've exported your data first" is in the wrong order. By the time the reader reaches the condition, they may have clicked already. I move the condition or context to the front: "If you've exported your data, click &lt;strong&gt;Delete&lt;/strong&gt;." Location works the same way: "In the &lt;strong&gt;Settings&lt;/strong&gt; panel, select &lt;strong&gt;Notifications&lt;/strong&gt;."&lt;/p&gt;

&lt;h2&gt;
  
  
  Say what the reader should see
&lt;/h2&gt;

&lt;p&gt;Most steps stop at the action. I add a short line saying what should happen: a message appears, a file is created, a new tab opens. That's how readers know the step worked, and how they notice a problem right away instead of several steps later. If the writer isn't sure what the result looks like, nobody has checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commands get their own code block
&lt;/h2&gt;

&lt;p&gt;A command buried in a sentence is hard to copy and easy to mistype. Each command gets its own code block, with the prose before it saying what it does and after it saying what to expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Move optional paths out of the steps
&lt;/h2&gt;

&lt;p&gt;"Alternatively, you can..." in the middle of a step forces a decision while the reader is busy following. If there are two real paths, such as cloud and self-hosted, I split them into two procedures or put the choice before step 1. Optional extras go in a note after the last step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the same verb for the same action
&lt;/h2&gt;

&lt;p&gt;Click, hit, tap, choose, pick: when a page mixes them, readers wonder if they mean different things. I agree on a small set, for example &lt;strong&gt;click&lt;/strong&gt; for buttons, &lt;strong&gt;select&lt;/strong&gt; for menu options, &lt;strong&gt;enter&lt;/strong&gt; for typing into a field, &lt;strong&gt;press&lt;/strong&gt; for keys, and match interface labels exactly, in bold.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before and after
&lt;/h2&gt;

&lt;p&gt;Here's a typical draft:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;1. Clone the repository and install the dependencies with &lt;span class="sb"&gt;`npm install`&lt;/span&gt; and then start the server with &lt;span class="sb"&gt;`npm run dev`&lt;/span&gt;.
2. Hit &lt;span class="gs"&gt;**Save**&lt;/span&gt;, or alternatively press Ctrl+S if you prefer, and if you're on the cloud version skip to step 5.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the same steps after editing. On the real page, the commands would be fenced code blocks; here they're indented so the example stays readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;1. Clone the repository and open its folder in a terminal.

2. Install the dependencies:

       npm install

   When it finishes, the project has a &lt;span class="sb"&gt;`node_modules`&lt;/span&gt; folder.

3. Start the development server:

       npm run dev

   The terminal shows the local address where the app is running.

4. In the app, click &lt;span class="gs"&gt;**Save**&lt;/span&gt;.

   A "Saved" message appears at the top of the page.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cloud path from the old step 2 moved out of the list entirely, into its own short section.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick check for crowded steps
&lt;/h2&gt;

&lt;p&gt;A small script helps me find steps worth a second look. It flags numbered lines with more than one "and" or more than one inline code span:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="no"&gt;STEP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;"^\s*\d+\.\s+(.*)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;"`[^`]+`"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;STEP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;"\band\b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;IGNORECASE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;commands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CODE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ands&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;commands&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"line {number}: {ands} x 'and', {commands} code spans"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"  {text.strip()}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save it as &lt;code&gt;check_steps.py&lt;/code&gt; and run it with the file name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 check_steps.py tutorial.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It only reads the first line of each step and can't tell a list of things from two actions, so it points me to places to look, not fixes. On the draft above, it flags step 1.&lt;/p&gt;

&lt;p&gt;The last check: follow the steps yourself, looking at the screen after each one. If you have to search the page to find where you were, that step needs another edit.&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>technicalwriting</category>
      <category>writing</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Editing the 'Before you begin' section so readers don't get stuck at step three</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Tue, 10 Nov 2026 09:09:01 +0000</pubDate>
      <link>https://dev.to/nataliakovac/editing-the-before-you-begin-section-so-readers-dont-get-stuck-at-step-three-khk</link>
      <guid>https://dev.to/nataliakovac/editing-the-before-you-begin-section-so-readers-dont-get-stuck-at-step-three-khk</guid>
      <description>&lt;p&gt;When a reader gets stuck at step three of a tutorial, the problem is often not step three. It's the "Before you begin" section, which promised the reader was ready when they weren't. They installed the wrong version, or they don't have the right permission, or the tutorial assumed they knew something it never mentioned.&lt;/p&gt;

&lt;p&gt;Prerequisites are usually written last and edited least. I've learned to give them a full editing pass of their own. Here's what I look for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vague items that can't be checked
&lt;/h2&gt;

&lt;p&gt;A typical first draft looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Prerequisites
&lt;/span&gt;
&lt;span class="k"&gt;- &lt;/span&gt;Node.js
&lt;span class="k"&gt;- &lt;/span&gt;Docker
&lt;span class="k"&gt;- &lt;/span&gt;A GitHub account
&lt;span class="k"&gt;- &lt;/span&gt;Basic knowledge of the command line
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every item is true, and almost none helps. Which Node.js version? Does Docker need to be running, or just installed? What does the GitHub account need to be able to do? And "basic knowledge" means something different to every reader.&lt;/p&gt;

&lt;p&gt;My test for each item: could a reader find out, in under a minute, whether they meet it? If not, the item needs editing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versions: give a number and a way to check
&lt;/h2&gt;

&lt;p&gt;If the tutorial depends on a minimum version, say so, and show the command that prints it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the writer doesn't know the minimum, I ask them to note the version they tested with. "Tested with Node.js 20" is honest and still useful: readers on an older version know where to look first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installed is not the same as ready
&lt;/h2&gt;

&lt;p&gt;Some tools can be installed but not usable. Docker is the classic case: the command exists, but the daemon isn't running, and the reader only finds out halfway through. A better check tests the thing the tutorial actually needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If Docker isn't running, this fails straight away with an error about not being able to connect to the daemon. That's much kinder at the top of the page than at step three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accounts and permissions
&lt;/h2&gt;

&lt;p&gt;"A GitHub account" hides two questions: is the reader signed in where the tutorial needs them to be, and do they have permission to do what the steps ask? If a step creates a repository in an organisation or adds a secret, the reader needs more than an account.&lt;/p&gt;

&lt;p&gt;Where a command exists to check this, I include it. For the GitHub CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For local permissions, on Linux, a reader can check whether they're in the &lt;code&gt;docker&lt;/code&gt; group, which is what lets them run Docker without &lt;code&gt;sudo&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;groups
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When there's no command, I ask the writer to name the role or permission exactly, using the same words the interface uses, so readers can find it in their settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assumed knowledge: name it and link it
&lt;/h2&gt;

&lt;p&gt;"Basic knowledge of the command line" doesn't tell anyone whether they qualify. I replace it with the specific things the tutorial expects readers to do without explanation: change directories, set an environment variable, edit a file in a terminal editor. Then I link one good introduction for readers who need it. They can decide for themselves, and nobody feels tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before and after
&lt;/h2&gt;

&lt;p&gt;Here's the same section after editing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Before you begin
&lt;/span&gt;
You'll need:

&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Node.js 20 or later.**&lt;/span&gt; Check with &lt;span class="sb"&gt;`node --version`&lt;/span&gt;.
&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Docker, installed and running.**&lt;/span&gt; Run &lt;span class="sb"&gt;`docker info`&lt;/span&gt;. If you
  see an error about connecting to the daemon, start Docker first.
&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**A GitHub account with permission to create repositories**&lt;/span&gt;
  in the organisation you'll use. Check you're signed in to the
  GitHub CLI with &lt;span class="sb"&gt;`gh auth status`&lt;/span&gt;.
&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Comfort with a few terminal basics:**&lt;/span&gt; changing directories,
  setting environment variables, and editing a text file.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's longer. It's also something a reader can work through like a checklist, and each line either passes or tells them what to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test it from a clean start
&lt;/h2&gt;

&lt;p&gt;The final check isn't an edit at all. I ask someone who didn't write the tutorial to follow the prerequisites on a machine that isn't already set up, or in a fresh container or virtual machine. Writers have everything installed already, so they can't see what's missing. A clean setup shows it in minutes.&lt;/p&gt;

&lt;p&gt;When a reader gets stuck now, I check this section first. Most of the time the fix is one more line in it.&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>writing</category>
      <category>beginners</category>
      <category>technicalwriting</category>
    </item>
    <item>
      <title>Editing headings in docs for readers who scan</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Sat, 07 Nov 2026 11:01:13 +0000</pubDate>
      <link>https://dev.to/nataliakovac/editing-headings-in-docs-for-readers-who-scan-1lf9</link>
      <guid>https://dev.to/nataliakovac/editing-headings-in-docs-for-readers-who-scan-1lf9</guid>
      <description>&lt;p&gt;Most people don't read documentation from top to bottom. They land on a page, scan for the part that matches their problem, and read only that. The headings are what they scan. When I edit a docs page, I treat the headings as a separate piece of writing, and I edit them before I touch a single paragraph.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the headings on their own first
&lt;/h2&gt;

&lt;p&gt;My first pass ignores the body text completely. I pull out just the headings and read them as a list, like a table of contents. For a Markdown file, I use a short Python script (more on it below), but copying them into a scratch file by hand works too.&lt;/p&gt;

&lt;p&gt;Then I ask one question: if this list were all I saw, could I find the section I need? Here's a typical list from an install guide before editing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Overview
Prerequisites
Install on macOS
  Verify the install
Configuration
  Advanced
Troubleshooting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not terrible, but "Overview", "Configuration" and "Advanced" don't tell a scanning reader much. Advanced what? Configuration of which part?&lt;/p&gt;

&lt;h2&gt;
  
  
  Name the task, not the category
&lt;/h2&gt;

&lt;p&gt;Category labels like "Configuration" or "Usage" describe what kind of content sits underneath. Task headings describe what the reader can do with it. Readers arrive with a task in mind, so task headings match what they're looking for.&lt;/p&gt;

&lt;p&gt;Some edits I make often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Configuration" becomes "Set your API key and default region"&lt;/li&gt;
&lt;li&gt;"Usage" becomes "Run your first sync"&lt;/li&gt;
&lt;li&gt;"Advanced" becomes "Use a proxy server"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The edited headings are longer. That's fine. A heading that is a few words longer but tells me exactly what's below saves more time than it costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put the distinctive words first
&lt;/h2&gt;

&lt;p&gt;When people scan, they mostly read the start of each line. If five headings in a row begin with "How to", the eye has to travel past the same two words every time to find the difference.&lt;/p&gt;

&lt;p&gt;So I move the words that tell sections apart to the front:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"How to configure logging" becomes "Configure logging"&lt;/li&gt;
&lt;li&gt;"Information about rate limits" becomes "Rate limits and how to stay under them"&lt;/li&gt;
&lt;li&gt;"Steps for upgrading from version 2" becomes "Upgrade from version 2"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Starting with the verb or the key noun means the first word or two already identify the section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep parallel headings parallel
&lt;/h2&gt;

&lt;p&gt;Headings at the same level under the same parent are siblings, and readers compare them. If one sibling is a verb phrase, one is a noun and one is a question, the list feels uneven and harder to scan.&lt;/p&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Installing on Linux
Windows
How do I install on macOS?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install on Linux
Install on Windows
Install on macOS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The edited version is a little repetitive, and that's the point. The repetition makes the one word that differs stand out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the reader's words for problems
&lt;/h2&gt;

&lt;p&gt;Troubleshooting sections are where headings matter most, because readers arrive with an error on their screen. A heading like "Path issues" makes them guess. A heading that quotes what they see, such as &lt;code&gt;"command not found" after installing&lt;/code&gt;, lets them match it instantly, and it's also the text they're likely to search for.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small script to list headings
&lt;/h2&gt;

&lt;p&gt;This is the script I use for the first pass. It prints every H2 to H4 heading with its line number, indents by level, skips fenced code blocks (where &lt;code&gt;#&lt;/code&gt; usually starts a comment), and marks a few headings I almost always end up rewriting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;VAGUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;overview&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;introduction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;general&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;details&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;miscellaneous&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;other&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;more information&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;advanced&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;in_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;in_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;in_code&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(#{2,4}) (.+)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;in_code&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  &amp;lt;- vague&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;VAGUE&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;python3 headings.py install.md&lt;/code&gt; on the guide above gives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   2  Overview  &amp;lt;- vague
   4  Prerequisites
   5  Install on macOS
   9    Verify the install
  10  Configuration
  11    Advanced  &amp;lt;- vague
  12  Troubleshooting
  13    "command not found" after installing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flag list is mine and deliberately short. A heading like "Overview" isn't always wrong; the flag is a prompt to check, not a verdict. The script also doesn't handle indented code blocks or headings written with underlines, which I rarely see in the docs I edit.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to stop
&lt;/h2&gt;

&lt;p&gt;I stop editing headings when the list on its own reads like a useful map of the page. Then I go back to the paragraphs, and often find that a clearer heading has already shown me which paragraphs belong somewhere else.&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>writing</category>
      <category>python</category>
      <category>technicalwriting</category>
    </item>
    <item>
      <title>Editing code samples in documentation: what I check before they ship</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Thu, 05 Nov 2026 11:46:48 +0000</pubDate>
      <link>https://dev.to/nataliakovac/editing-code-samples-in-documentation-what-i-check-before-they-ship-3nn2</link>
      <guid>https://dev.to/nataliakovac/editing-code-samples-in-documentation-what-i-check-before-they-ship-3nn2</guid>
      <description>&lt;p&gt;When I edit a page of documentation, I used to skim past the code blocks. They looked technical, someone had presumably tested them, and my job was the prose around them. That was a mistake. The code samples are often the only part of a page a reader actually uses. Many people jump straight to the first grey box, copy it, and paste it into a terminal. If it fails, the clear paragraph above it doesn't help much.&lt;/p&gt;

&lt;p&gt;So now code samples get an editing pass of their own. Here is what I check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can it be copied and run as is?
&lt;/h2&gt;

&lt;p&gt;This is the first question, and the answer is "no" more often than you'd think. The usual problems are small:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A shell prompt (&lt;code&gt;$&lt;/code&gt; or &lt;code&gt;&amp;gt;&lt;/code&gt;) at the start of each line, which gets pasted along with the command&lt;/li&gt;
&lt;li&gt;Command and output mixed in one block, so the reader copies both&lt;/li&gt;
&lt;li&gt;A step that depends on something the page never mentioned, like being in a certain folder&lt;/li&gt;
&lt;li&gt;Curly quotes that crept in when the text passed through a word processor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fix for the first two is the same: keep commands and output in separate blocks. Put the command in a block marked as &lt;code&gt;bash&lt;/code&gt;, and the output in a block marked as &lt;code&gt;text&lt;/code&gt;, introduced with a short line like "You should see something like this:".&lt;/p&gt;

&lt;h2&gt;
  
  
  Are placeholders obvious?
&lt;/h2&gt;

&lt;p&gt;A sample like &lt;code&gt;git clone https://example.com/project.git&lt;/code&gt; is fine as long as readers know which part to replace. When they don't, they either paste it unchanged or guess. I ask writers to use one style for placeholders across the whole set of docs, for example &lt;code&gt;&amp;lt;your-project-name&amp;gt;&lt;/code&gt;, and to say right after the block what each placeholder means.&lt;/p&gt;

&lt;p&gt;The angle brackets have a useful side effect. If someone pastes the line without replacing them, the shell treats &lt;code&gt;&amp;lt;&lt;/code&gt; as a redirect and the command fails straight away, instead of quietly doing the wrong thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does the text match the code?
&lt;/h2&gt;

&lt;p&gt;Prose and code drift apart. A paragraph says "set &lt;code&gt;timeout&lt;/code&gt; to 30" while the block below sets &lt;code&gt;timeout: 60&lt;/code&gt;, because someone updated one and not the other. I read each sample next to the sentence that introduces it and check names, values and file paths line by line. It's slow and boring, and it catches something more often than I'd like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it the shortest sample that works?
&lt;/h2&gt;

&lt;p&gt;Long samples hide the point. If a page explains one configuration option, the reader doesn't need forty lines of unrelated settings around it. I suggest cutting to the lines that matter, and saying in the text that the rest of the file stays as it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let a script do the dull part
&lt;/h2&gt;

&lt;p&gt;In a docs-as-code setup, the pages are Markdown files in a repository, so some of these checks can run automatically. This small Python script finds every &lt;code&gt;bash&lt;/code&gt; or &lt;code&gt;sh&lt;/code&gt; block in the files you give it, flags lines that start with a &lt;code&gt;$&lt;/code&gt; prompt, and asks &lt;code&gt;bash -n&lt;/code&gt; to check the syntax without running anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;FENCE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^```

(\w+)\s*\n(.*?)^

```\s*$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MULTILINE&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOTALL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;problems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;FENCE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finditer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shell&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^\s*\$ &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MULTILINE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: prompt &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; inside a copyable block&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;problems&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: syntax error&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;problems&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;problems&lt;/span&gt;

&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;check_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; problem(s) found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save it as &lt;code&gt;check_samples.py&lt;/code&gt; and point it at your docs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 check_samples.py docs/&lt;span class="k"&gt;*&lt;/span&gt;.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a test page with a prompt in one block and an unclosed &lt;code&gt;if&lt;/code&gt; in another, it reports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/install.md:3: prompt '$' inside a copyable block
docs/install.md:7: syntax error
bash: line 3: syntax error: unexpected end of file
2 problem(s) found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The line numbers point to the opening fence of each block. The script exits with status 1 when it finds something, so it can run as a step in CI and fail the build.&lt;/p&gt;

&lt;p&gt;It won't tell you whether a command does the right thing, only that it parses. That still matters: a sample that can't even be parsed is one nobody tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then run them for real
&lt;/h2&gt;

&lt;p&gt;The last check is the one no script replaces. Before a page goes out, I follow it from top to bottom in a fresh terminal, copying every block exactly as a reader would. Whatever breaks is an edit, even if the prose around it is perfect.&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>technicalwriting</category>
      <category>markdown</category>
      <category>python</category>
    </item>
    <item>
      <title>Tables in documentation: when they help and when they get in the way</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Sat, 31 Oct 2026 10:08:45 +0000</pubDate>
      <link>https://dev.to/nataliakovac/tables-in-documentation-when-they-help-and-when-they-get-in-the-way-11mf</link>
      <guid>https://dev.to/nataliakovac/tables-in-documentation-when-they-help-and-when-they-get-in-the-way-11mf</guid>
      <description>&lt;p&gt;Tables are one of the first things I look at when I edit documentation. Sometimes a table is the clearest part of a page. Other times it's where the page falls apart: cells full of paragraphs, a column nobody needs, or a sequence of steps forced into rows.&lt;/p&gt;

&lt;p&gt;Here is how I decide whether a table should stay, and what I change when it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  A table is for comparing
&lt;/h2&gt;

&lt;p&gt;A table works when the reader wants to compare several items across the same set of attributes. Plans and their limits, configuration options and their defaults, API parameters and their types. The reader's eyes move across a row or down a column, and the grid makes that easy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Option    | Type    | Default | Description                         |
|-----------|---------|---------|-------------------------------------|
| &lt;span class="sb"&gt;`timeout`&lt;/span&gt; | integer | &lt;span class="sb"&gt;`30`&lt;/span&gt;    | Seconds to wait before giving up.   |
| &lt;span class="sb"&gt;`retries`&lt;/span&gt; | integer | &lt;span class="sb"&gt;`3`&lt;/span&gt;     | How many times to retry on failure. |
| &lt;span class="sb"&gt;`verbose`&lt;/span&gt; | boolean | &lt;span class="sb"&gt;`false`&lt;/span&gt; | Print each request to the console.  |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every row answers the same questions in the same order. That's the test I use: if the rows don't share the same columns naturally, it probably isn't a table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps don't belong in a table
&lt;/h2&gt;

&lt;p&gt;A common pattern is a table with "Step" and "Action" columns. It looks organised, but it adds nothing a numbered list doesn't already do, and it's harder to read on a narrow screen. Lists also give each step room for a short note or a code block, which a table cell handles badly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;1.&lt;/span&gt; Open &lt;span class="gs"&gt;**Settings**&lt;/span&gt; and select &lt;span class="gs"&gt;**API keys**&lt;/span&gt;.
&lt;span class="p"&gt;2.&lt;/span&gt; Select &lt;span class="gs"&gt;**Create key**&lt;/span&gt;.
&lt;span class="p"&gt;3.&lt;/span&gt; Copy the key and store it somewhere safe. It's only shown once.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Keep cells short
&lt;/h2&gt;

&lt;p&gt;If a cell needs more than a sentence or two, the content usually belongs somewhere else. I move longer explanations into the text below the table, or into a separate section, and keep the cell to a short summary. A table full of paragraphs forces the reader to scroll sideways or read text squeezed into a narrow column.&lt;/p&gt;

&lt;p&gt;Many Markdown flavours, including GitHub Flavored Markdown, don't support lists or multiple paragraphs inside a table cell anyway, which is a useful hint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the headers do the work
&lt;/h2&gt;

&lt;p&gt;Column headers are where the reader looks first, and some screen readers announce them together with each cell. So I make them specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Put units in the header, not in every cell: &lt;code&gt;Timeout (seconds)&lt;/code&gt; instead of &lt;code&gt;30 seconds&lt;/code&gt; in each row.&lt;/li&gt;
&lt;li&gt;Match the name used in the code or on screen. If the setting is called &lt;code&gt;retries&lt;/code&gt;, the header doesn't say "Attempts".&lt;/li&gt;
&lt;li&gt;Avoid empty headers. A blank first header above a column of names makes the table harder to follow when it's read aloud.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Don't leave cells empty
&lt;/h2&gt;

&lt;p&gt;An empty cell can mean "no", "not applicable", "unknown" or "someone forgot". The reader has no way to tell which. I write the actual answer, such as "None", "Not supported" or "Not applicable", and I use the same wording throughout the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Order the rows on purpose
&lt;/h2&gt;

&lt;p&gt;Alphabetical order is fine when the reader is looking something up by name. When most readers only need two or three rows, I put those first, or I split the table into "common options" and "advanced options". Either way, I want the order to be a choice, not whatever order the rows were added in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch out for pipes and alignment
&lt;/h2&gt;

&lt;p&gt;Two small Markdown details catch people out. A literal pipe character inside a cell breaks the column structure unless it's escaped, even inside inline code in GitHub Flavored Markdown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Operator | Meaning    |
|----------|------------|
| &lt;span class="sb"&gt;`a \| b`&lt;/span&gt; | a or b     |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And colons in the separator row control alignment. Numbers are easier to compare when they're right-aligned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Plan  | Users | Storage (GB) |
|:------|------:|-------------:|
| Free  |     1 |            5 |
| Team  |    10 |          100 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  One last test
&lt;/h2&gt;

&lt;p&gt;My last step is to read one row from left to right and ask whether it makes sense as a sentence: "The &lt;code&gt;timeout&lt;/code&gt; option is an integer, defaults to 30, and sets the seconds to wait." If a row can't be read that way, the columns are probably mixing different kinds of information, and the table needs another edit.&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>technicalwriting</category>
      <category>markdown</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Editing changelogs so people can actually use them</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Thu, 29 Oct 2026 10:08:29 +0000</pubDate>
      <link>https://dev.to/nataliakovac/editing-changelogs-so-people-can-actually-use-them-3aio</link>
      <guid>https://dev.to/nataliakovac/editing-changelogs-so-people-can-actually-use-them-3aio</guid>
      <description>&lt;p&gt;Changelogs are a strange kind of document. Almost everyone who uses a project reads them at some point, usually right before an upgrade, and usually in a hurry. Yet they're often written last, quickly, and by copying commit messages into a list.&lt;/p&gt;

&lt;p&gt;When I edit a changelog, I try to read it as the person who has to decide whether to upgrade today. Here's what I look for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commit messages are not changelog entries
&lt;/h2&gt;

&lt;p&gt;A commit message is written for the people working on the code. A changelog entry is written for the people using it. The two overlap, but not much.&lt;/p&gt;

&lt;p&gt;To see what changed since the last release, I start with the commit list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; v1.4.0..HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows every commit after the &lt;code&gt;v1.4.0&lt;/code&gt; tag, one per line. It's raw material, not the changelog. Lines like &lt;code&gt;fix typo&lt;/code&gt;, &lt;code&gt;refactor parser&lt;/code&gt;, or &lt;code&gt;bump deps&lt;/code&gt; may matter to contributors, but most users don't need them. What I want are the changes a user would notice: something new, something that behaves differently, something that stopped working, or something that got fixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Group by what the reader needs to do
&lt;/h2&gt;

&lt;p&gt;A flat list of twenty items makes the reader do the sorting. I prefer the grouping from the Keep a Changelog convention: Added, Changed, Deprecated, Removed, Fixed, and Security. Even if a project doesn't follow that convention fully, the headings answer the questions people actually have.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## [1.5.0] - 2026-10-29&lt;/span&gt;

&lt;span class="gu"&gt;### Added&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Export to CSV from the Reports page.

&lt;span class="gu"&gt;### Changed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Dates in exported files now use the YYYY-MM-DD format.

&lt;span class="gu"&gt;### Fixed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Search no longer ignores words with accents.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything under Changed or Removed deserves a second look, because that's where upgrades break.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lead with the effect, not the code
&lt;/h2&gt;

&lt;p&gt;Here's a typical entry before editing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Refactored date handling in exporter module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And after:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Dates in exported files now use the YYYY-MM-DD format.
  If you parse exports with a script, update the date format there.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first version describes work that was done. The second describes what the reader will see, and what they might need to do about it. I ask myself one question for each entry: if this were the only line someone read, would they know whether it affects them?&lt;/p&gt;

&lt;h2&gt;
  
  
  Make breaking changes impossible to miss
&lt;/h2&gt;

&lt;p&gt;A breaking change hidden in the middle of a list is the most expensive mistake a changelog can make. I move these to the top of the release section and mark them clearly, so nobody has to search for them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### Removed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Breaking:**&lt;/span&gt; the &lt;span class="sb"&gt;`--legacy-output`&lt;/span&gt; option is gone.
  Use &lt;span class="sb"&gt;`--format=v1`&lt;/span&gt; for the old output.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The replacement goes right next to the removal. "Removed X" on its own leaves the reader with a problem; "Removed X, use Y instead" gives them a way forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the same words as the interface
&lt;/h2&gt;

&lt;p&gt;If a button says "Export", the changelog says "Export", not "download", "save as file" or "data dump". Readers search changelogs for the words they see on screen or type in the terminal. Keeping the names identical makes those searches work, and it matches the rest of the docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Date and order consistently
&lt;/h2&gt;

&lt;p&gt;Two small rules save a lot of confusion. First, newest release at the top. Second, one date format everywhere. I use YYYY-MM-DD because it doesn't mean different things in different countries, and it sorts correctly as plain text.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick read before it ships
&lt;/h2&gt;

&lt;p&gt;My last check is simple. I read only the section headings and the first few words of each entry. If that skim tells me what changed and whether I need to act, the changelog does its job. If I have to read every line to find the one breaking change, it goes back for another edit.&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>writing</category>
      <category>opensource</category>
      <category>git</category>
    </item>
    <item>
      <title>Writing alt text for screenshots in documentation</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Tue, 27 Oct 2026 10:06:02 +0000</pubDate>
      <link>https://dev.to/nataliakovac/writing-alt-text-for-screenshots-in-documentation-4pi0</link>
      <guid>https://dev.to/nataliakovac/writing-alt-text-for-screenshots-in-documentation-4pi0</guid>
      <description>&lt;p&gt;Screenshots are everywhere in software docs, and most of them have alt text like &lt;code&gt;screenshot&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt;, or the original file name. Sometimes there's none at all. When I edit a guide, the images are often the last thing anyone has looked at closely.&lt;/p&gt;

&lt;p&gt;Alt text matters more in docs than people think. Screen reader users hear it instead of seeing the image. It shows up when an image fails to load, for example on a slow connection or after someone renames a folder in the repo. And it's text, so it can be searched and translated, which a picture of text can't.&lt;/p&gt;

&lt;p&gt;Here's how I approach it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask what the screenshot is for
&lt;/h2&gt;

&lt;p&gt;Before writing anything, I ask one question: why is this image here? In docs, the answer is almost always one of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It shows &lt;strong&gt;where&lt;/strong&gt; something is (a button, a menu, a field).&lt;/li&gt;
&lt;li&gt;It shows &lt;strong&gt;what you should see&lt;/strong&gt; after a step, so the reader can confirm it worked.&lt;/li&gt;
&lt;li&gt;It shows a &lt;strong&gt;specific value or setting&lt;/strong&gt; the reader has to match.&lt;/li&gt;
&lt;li&gt;It's &lt;strong&gt;decoration&lt;/strong&gt;, and the surrounding text already says everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The alt text should carry that purpose, not a full inventory of the screen. A settings page might have thirty controls on it, but if the step is about one checkbox, that checkbox is what the alt text is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Describe the state, not the pixels
&lt;/h2&gt;

&lt;p&gt;Compare these two:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Screenshot of the settings page&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;images/settings.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;The Notifications tab with "Email me when a build fails" turned on&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;images/settings.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first tells me nothing I couldn't guess. The second tells me exactly what the screen should look like after the step, which is the whole reason the screenshot exists.&lt;/p&gt;

&lt;p&gt;A few habits that help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skip "image of" and "screenshot of".&lt;/strong&gt; Screen readers usually announce that it's an image already. Start with the content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the exact UI labels&lt;/strong&gt;, with the same capitalisation as the interface. If the button says "Save changes", the alt text says "Save changes", not "the save button".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include values that matter.&lt;/strong&gt; If the reader needs to pick "UTF-8" or set a timeout to 30, put that in the alt text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it to a sentence or two.&lt;/strong&gt; If you need more, the information probably belongs in the body text.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Don't hide instructions in the image
&lt;/h2&gt;

&lt;p&gt;This is the problem I find most often. A step says "Configure the options as shown below", and the actual settings only exist in the screenshot. Anyone who can't see the image, or whose image didn't load, is stuck.&lt;/p&gt;

&lt;p&gt;The fix isn't longer alt text. It's moving the information into the step itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;3.&lt;/span&gt; In &lt;span class="gs"&gt;**Format**&lt;/span&gt;, select &lt;span class="gs"&gt;**CSV**&lt;/span&gt;, and in &lt;span class="gs"&gt;**Encoding**&lt;/span&gt;, select &lt;span class="gs"&gt;**UTF-8**&lt;/span&gt;.

   !&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;The Export dialog with CSV and UTF-8 selected&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;images/export.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the step works without the image, and the screenshot becomes a confirmation. The alt text can stay short because the text above it does the heavy lifting.&lt;/p&gt;

&lt;h2&gt;
  
  
  When empty alt text is right
&lt;/h2&gt;

&lt;p&gt;Not every image needs a description. If a screenshot only repeats what the text already says, or it's a decorative banner, an empty alt is the honest choice. In Markdown that's &lt;code&gt;![](images/banner.png)&lt;/code&gt;, which renders as &lt;code&gt;alt=""&lt;/code&gt;. Screen readers generally skip images with empty alt text instead of reading out the file name.&lt;/p&gt;

&lt;p&gt;The difference between "empty on purpose" and "forgot to write it" is invisible in the source, though. In repos I work on, I like a short HTML comment next to deliberate ones, so the next editor doesn't "fix" it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- decorative, text above covers it --&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;![](&lt;/span&gt;&lt;span class="sx"&gt;images/banner.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A quick check before review
&lt;/h2&gt;

&lt;p&gt;To find the obvious problems in a docs folder, I use a single &lt;code&gt;grep&lt;/code&gt;. It looks for three patterns: empty or generic alt text, alt text that is a file name, and alt text that starts with "image of" or "screenshot of".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rniE&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'!\[(image|screenshot|picture|img)?\]\('&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'!\[[^]]*\.(png|jpe?g|gif|webp)\]'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'!\[(an? )?(image|picture|screenshot|photo) (of|showing)'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  docs/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-r&lt;/code&gt; searches the folder recursively, &lt;code&gt;-n&lt;/code&gt; adds line numbers, &lt;code&gt;-i&lt;/code&gt; ignores case, and &lt;code&gt;-E&lt;/code&gt; enables extended regular expressions. Each &lt;code&gt;-e&lt;/code&gt; adds one pattern. On a test file it prints something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/setup.md:3:![](images/settings.png)
docs/setup.md:5:![screenshot](images/login.png)
docs/setup.md:7:![Screenshot 2026-03-02 at 10.14.png](images/export.png)
docs/setup.md:11:![image of the dashboard](img/dash.png)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not a verdict. The empty alt on line 3 might be deliberate, and the check can't tell whether a real description is accurate. It only catches images written in Markdown syntax, not HTML &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags. But it gives me a list to work through, which beats scrolling every page looking for images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep it in sync
&lt;/h2&gt;

&lt;p&gt;The last thing: alt text goes stale with the UI. When a button gets renamed and someone updates the screenshot, the alt text often keeps the old label. When I review a docs change that touches an image, I read its alt text against the new screenshot. It takes a few seconds, and it's usually the only place the old wording survives.&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>a11y</category>
      <category>writing</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Writing alt text for screenshots in documentation</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Sun, 25 Oct 2026 10:14:12 +0000</pubDate>
      <link>https://dev.to/nataliakovac/writing-alt-text-for-screenshots-in-documentation-51jm</link>
      <guid>https://dev.to/nataliakovac/writing-alt-text-for-screenshots-in-documentation-51jm</guid>
      <description>&lt;p&gt;Screenshots are everywhere in software docs, and most of them have alt text like &lt;code&gt;screenshot&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt;, or the original file name. Sometimes there's none at all. When I edit a guide, the images are often the last thing anyone has looked at closely.&lt;/p&gt;

&lt;p&gt;Alt text matters more in docs than people think. Screen reader users hear it instead of seeing the image. It shows up when an image fails to load, for example on a slow connection or after someone renames a folder in the repo. And it's text, so it can be searched and translated, which a picture of text can't.&lt;/p&gt;

&lt;p&gt;Here's how I approach it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask what the screenshot is for
&lt;/h2&gt;

&lt;p&gt;Before writing anything, I ask one question: why is this image here? In docs, the answer is almost always one of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It shows &lt;strong&gt;where&lt;/strong&gt; something is (a button, a menu, a field).&lt;/li&gt;
&lt;li&gt;It shows &lt;strong&gt;what you should see&lt;/strong&gt; after a step, so the reader can confirm it worked.&lt;/li&gt;
&lt;li&gt;It shows a &lt;strong&gt;specific value or setting&lt;/strong&gt; the reader has to match.&lt;/li&gt;
&lt;li&gt;It's &lt;strong&gt;decoration&lt;/strong&gt;, and the surrounding text already says everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The alt text should carry that purpose, not a full inventory of the screen. A settings page might have thirty controls on it, but if the step is about one checkbox, that checkbox is what the alt text is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Describe the state, not the pixels
&lt;/h2&gt;

&lt;p&gt;Compare these two:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Screenshot of the settings page&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;images/settings.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;The Notifications tab with "Email me when a build fails" turned on&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;images/settings.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first tells me nothing I couldn't guess. The second tells me exactly what the screen should look like after the step, which is the whole reason the screenshot exists.&lt;/p&gt;

&lt;p&gt;A few habits that help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skip "image of" and "screenshot of".&lt;/strong&gt; Screen readers usually announce that it's an image already. Start with the content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the exact UI labels&lt;/strong&gt;, with the same capitalisation as the interface. If the button says "Save changes", the alt text says "Save changes", not "the save button".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include values that matter.&lt;/strong&gt; If the reader needs to pick "UTF-8" or set a timeout to 30, put that in the alt text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it to a sentence or two.&lt;/strong&gt; If you need more, the information probably belongs in the body text.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Don't hide instructions in the image
&lt;/h2&gt;

&lt;p&gt;This is the problem I find most often. A step says "Configure the options as shown below", and the actual settings only exist in the screenshot. Anyone who can't see the image, or whose image didn't load, is stuck.&lt;/p&gt;

&lt;p&gt;The fix isn't longer alt text. It's moving the information into the step itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;3.&lt;/span&gt; In &lt;span class="gs"&gt;**Format**&lt;/span&gt;, select &lt;span class="gs"&gt;**CSV**&lt;/span&gt;, and in &lt;span class="gs"&gt;**Encoding**&lt;/span&gt;, select &lt;span class="gs"&gt;**UTF-8**&lt;/span&gt;.

   !&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;The Export dialog with CSV and UTF-8 selected&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;images/export.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the step works without the image, and the screenshot becomes a confirmation. The alt text can stay short because the text above it does the heavy lifting.&lt;/p&gt;

&lt;h2&gt;
  
  
  When empty alt text is right
&lt;/h2&gt;

&lt;p&gt;Not every image needs a description. If a screenshot only repeats what the text already says, or it's a decorative banner, an empty alt is the honest choice. In Markdown that's &lt;code&gt;![](images/banner.png)&lt;/code&gt;, which renders as &lt;code&gt;alt=""&lt;/code&gt;. Screen readers generally skip images with empty alt text instead of reading out the file name.&lt;/p&gt;

&lt;p&gt;The difference between "empty on purpose" and "forgot to write it" is invisible in the source, though. In repos I work on, I like a short HTML comment next to deliberate ones, so the next editor doesn't "fix" it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- decorative, text above covers it --&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;![](&lt;/span&gt;&lt;span class="sx"&gt;images/banner.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A quick check before review
&lt;/h2&gt;

&lt;p&gt;To find the obvious problems in a docs folder, I use a single &lt;code&gt;grep&lt;/code&gt;. It looks for three patterns: empty or generic alt text, alt text that is a file name, and alt text that starts with "image of" or "screenshot of".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rniE&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'!\[(image|screenshot|picture|img)?\]\('&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'!\[[^]]*\.(png|jpe?g|gif|webp)\]'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'!\[(an? )?(image|picture|screenshot|photo) (of|showing)'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  docs/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-r&lt;/code&gt; searches the folder recursively, &lt;code&gt;-n&lt;/code&gt; adds line numbers, &lt;code&gt;-i&lt;/code&gt; ignores case, and &lt;code&gt;-E&lt;/code&gt; enables extended regular expressions. Each &lt;code&gt;-e&lt;/code&gt; adds one pattern. On a test file it prints something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/setup.md:3:![](images/settings.png)
docs/setup.md:5:![screenshot](images/login.png)
docs/setup.md:7:![Screenshot 2026-03-02 at 10.14.png](images/export.png)
docs/setup.md:11:![image of the dashboard](img/dash.png)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not a verdict. The empty alt on line 3 might be deliberate, and the check can't tell whether a real description is accurate. It only catches images written in Markdown syntax, not HTML &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags. But it gives me a list to work through, which beats scrolling every page looking for images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep it in sync
&lt;/h2&gt;

&lt;p&gt;The last thing: alt text goes stale with the UI. When a button gets renamed and someone updates the screenshot, the alt text often keeps the old label. When I review a docs change that touches an image, I read its alt text against the new screenshot. It takes a few seconds, and it's usually the only place the old wording survives.&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>a11y</category>
      <category>writing</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Editing error messages: what happened, why, and what to do next</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Fri, 23 Oct 2026 09:11:01 +0000</pubDate>
      <link>https://dev.to/nataliakovac/editing-error-messages-what-happened-why-and-what-to-do-next-33f7</link>
      <guid>https://dev.to/nataliakovac/editing-error-messages-what-happened-why-and-what-to-do-next-33f7</guid>
      <description>&lt;p&gt;When I edit documentation, the error messages are often the part nobody asked me to look at. They live in the code, not in the docs folder, so they slip past review. Yet they are probably read more carefully than any page I edit, because the person reading one is stuck and wants to get unstuck.&lt;/p&gt;

&lt;p&gt;Over time I've ended up with a simple test for any error message. It should answer three questions, roughly in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What happened?&lt;/li&gt;
&lt;li&gt;Why did it happen, if we know?&lt;/li&gt;
&lt;li&gt;What can the reader do now?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most weak messages answer only the first one, and some don't even manage that.&lt;/p&gt;

&lt;h2&gt;
  
  
  A before and after
&lt;/h2&gt;

&lt;p&gt;Here's the kind of message I see a lot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: invalid input
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Invalid how? Which input? The reader now has to guess, search, or read the source. A rewrite using the three questions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Couldn't save the project: the name "my project!" contains a character
that isn't allowed. Use only letters, numbers, hyphens and underscores,
for example "my-project".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's longer, but every part does a job. The first clause says what failed. The middle names the actual cause and repeats the value the reader typed, so they can see the problem instead of hunting for it. The last part gives a rule and an example they can copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Say what failed in the reader's terms
&lt;/h2&gt;

&lt;p&gt;Messages written from inside the code tend to describe the code. "NullReferenceException in ProjectService" is useful in a log, but the reader didn't do anything to a ProjectService. They clicked Save. So the message should start from the action they took: "Couldn't save the project".&lt;/p&gt;

&lt;p&gt;If you need the technical detail for debugging, keep it, but put it after the human part or in a "details" section. Nobody should have to read a stack trace to find out their file is too big.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't blame, don't joke
&lt;/h2&gt;

&lt;p&gt;"You entered an invalid date" and "That date isn't in a format we recognise" carry the same information. The second one doesn't point a finger. It's a small edit, and it makes a difference to someone who is already frustrated.&lt;/p&gt;

&lt;p&gt;I'm also wary of jokes and cute phrasing in errors. "Oops, something went sideways!" might be charming the first time. The fifth time, when you've lost your work, it's grating. Plain and calm reads better under stress.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the next step concrete
&lt;/h2&gt;

&lt;p&gt;"Please try again" is only good advice if trying again actually helps. If the fix is to change something, say what and how. If the reader can't fix it, say who can or where to look. A few patterns I reach for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give the allowed format with an example: "Use YYYY-MM-DD, for example 2026-03-14."&lt;/li&gt;
&lt;li&gt;Name the setting or file: "Check the &lt;code&gt;timeout&lt;/code&gt; value in settings.json."&lt;/li&gt;
&lt;li&gt;Point to a specific docs page, not the docs home page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A small code example
&lt;/h2&gt;

&lt;p&gt;Even in a short script you can make an error helpful. Compare a bare failure with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;config_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;config_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;FileNotFoundError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Couldn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t find the config file at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;config_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Create it by copying config.example.toml &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;into the same folder.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;config_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nf"&gt;load_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;config.toml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it without a &lt;code&gt;config.toml&lt;/code&gt; and the last line of the traceback reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FileNotFoundError: Couldn't find the config file at /home/you/app/config.toml. Create it by copying config.example.toml into the same folder.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Printing the full resolved path is the detail I like most here. A surprising number of "file not found" problems turn out to be "the script was looking in a different folder than I thought", and the absolute path makes that obvious in one glance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collect them in one place
&lt;/h2&gt;

&lt;p&gt;The most useful editing trick I know for error messages is to stop reading them one at a time. If a project keeps its messages in a single file, or you can pull them out with a quick search, read them all together in a list. Inconsistencies jump out right away: "Couldn't" in one place and "Unable to" in another, "folder" next to "directory", some messages ending with a full stop and some without. Pick one of each and apply it everywhere.&lt;/p&gt;

&lt;p&gt;Then do one last check: trigger a few of the errors yourself and read them in context, on the screen where they actually appear. A message that reads fine in a list can be cut off in a narrow dialog, or show up somewhere the reader won't notice it. That's still part of the edit.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>ux</category>
      <category>documentation</category>
      <category>programming</category>
    </item>
    <item>
      <title>Six small edits that make technical docs easier to follow</title>
      <dc:creator>Natália Kováč</dc:creator>
      <pubDate>Wed, 21 Oct 2026 17:55:01 +0000</pubDate>
      <link>https://dev.to/nataliakovac/six-small-edits-that-make-technical-docs-easier-to-follow-26ih</link>
      <guid>https://dev.to/nataliakovac/six-small-edits-that-make-technical-docs-easier-to-follow-26ih</guid>
      <description>&lt;p&gt;A lot of documentation is technically correct and still hard to use. The information is there, but the reader has to work to get it out. Most of the time the fix isn't a rewrite. It's a handful of small, repeatable edits.&lt;/p&gt;

&lt;p&gt;These are the ones I make most often when I edit docs, READMEs and how-to guides.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Put the goal before the instruction
&lt;/h3&gt;

&lt;p&gt;Readers scan for the thing they want to do. Make that the first thing they see.&lt;/p&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Run &lt;code&gt;npm run build -- --analyze&lt;/code&gt; if you want to see which packages make the bundle large.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To see which packages make the bundle large, run &lt;code&gt;npm run build -- --analyze&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Same words, but the reader can now decide in the first few words whether the sentence is for them.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. One action per step
&lt;/h3&gt;

&lt;p&gt;Numbered steps that hide three actions in one step are where people get lost.&lt;/p&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;.env&lt;/code&gt; file, add your API key and restart the server.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;After:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Create a file called &lt;code&gt;.env&lt;/code&gt; in the project root.&lt;/li&gt;
&lt;li&gt;Add your API key: &lt;code&gt;API_KEY=your-key-here&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Restart the server.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;More steps, but each one is easy to finish and easy to come back to if something goes wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Say what success looks like
&lt;/h3&gt;

&lt;p&gt;After an important step, tell the reader what they should see. Otherwise they don't know whether to continue or start debugging.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Run &lt;code&gt;docker compose up&lt;/code&gt;. When the setup works, the last line of the output is &lt;code&gt;Server listening on port 3000&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This one edit removes a lot of "is it supposed to do this?" questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Put conditions and warnings before the step
&lt;/h3&gt;

&lt;p&gt;If a step only applies in some cases, or can break something, say so before the command, not after it.&lt;/p&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Run &lt;code&gt;make reset-db&lt;/code&gt;. This deletes all local data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; the next command deletes all local data. Run &lt;code&gt;make reset-db&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;People copy and paste. By the time they read the sentence after the command, it has already run.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Define a term the first time, then stick to it
&lt;/h3&gt;

&lt;p&gt;If you call something a "workspace" in one section, a "project" in the next and an "environment" later, readers will assume these are three different things. Pick one word, explain it briefly the first time it appears, and use it consistently. A short glossary helps if the docs use many specialised terms.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Cut "simply", "just" and "easy"
&lt;/h3&gt;

&lt;p&gt;"Simply configure the proxy" is fine for the person who already knows how. For everyone else it adds a small sting: if it's simple and I'm stuck, the problem must be me. These words rarely add information, so removing them costs nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  A quick way to apply these
&lt;/h3&gt;

&lt;p&gt;When I edit a doc, I do one pass per edit instead of trying to fix everything at once:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read only the headings and first sentences. Is the goal always up front?&lt;/li&gt;
&lt;li&gt;Read only the numbered steps. One action each? Success described?&lt;/li&gt;
&lt;li&gt;Search for "simply", "just" and "easy".&lt;/li&gt;
&lt;li&gt;Search for every key term and check it's used the same way.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each pass is quick, and doing them separately means I actually notice the problems instead of skimming past them.&lt;/p&gt;

&lt;p&gt;None of this needs a tool or a style guide. It just needs someone to read the doc as a person who has never seen the project before. If you can, ask a new teammate to follow your guide while you watch. You'll find the confusing step within minutes.&lt;/p&gt;

&lt;p&gt;What edits do you find yourself making again and again in docs?&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>writing</category>
      <category>technicalwriting</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
