January 2nd, 2025

Rules for writing software tutorials

Effective software tutorials should be beginner-friendly, clearly indicate outcomes, explain relevance, provide easily copyable code snippets, and use long command-line flags to enhance clarity and accessibility.

Read original articleLink Icon
Rules for writing software tutorials

Most software tutorials are often flawed due to a lack of clarity and an assumption of prior knowledge that beginners may not possess. To create effective tutorials, authors should focus on several key principles. First, tutorials should be written for beginners, avoiding jargon and complex terminology. Titles must promise a clear outcome, allowing readers to understand what they will achieve. The introduction should explain the tutorial's goal and its relevance to the reader's needs. Additionally, showing the end result early on helps set expectations. Code snippets should be easily copyable, avoiding common pitfalls like including shell prompts or requiring user input. Authors should use long command-line flags for clarity and separate user-defined values from reusable logic to prevent confusion. By adhering to these guidelines, tutorial writers can significantly improve the quality and accessibility of their content, making it easier for beginners to follow along and learn effectively.

- Tutorials should be beginner-friendly, avoiding complex terminology.

- Titles must clearly indicate the outcome of the tutorial.

- Introductions should explain the tutorial's relevance and goals.

- Code snippets should be copyable and free from interactive prompts.

- Use long command-line flags and separate user-defined values for clarity.

Link Icon 35 comments
By @stared - 4 months
There is a lot of good advice about details!

Especially one that got my heart:

> Some authors design their tutorials the way you’d give instructions for an origami structure. It’s a mysterious sequence of twists and folds until you get to the end, and then: wow, it’s a beautiful swan!

> A grand finale might be fun for origami, but it’s stressful for the reader."

Yes, a lot of tutorials are puzzle games. You need to guess other tools to install, which are obvious to the author, but not everyone.

I would add a few things:

* Have two types of examples - minimal and the most typical (one is to show the essence without distraction, the second to serve as a practical starting point) * Always provide the full code sequence to run code; if there are any assumptions, these should be listed explicitly (e.g. "it needs Node 22"); you hinted a bit, but since many tutorials miss that, it deserves attention.

Even better, if it is possible to combine it into one point and make it runnable. For example, for a package I had been developing, livelossplot, I made Jupyter Notebooks runnable in Colab:

* https://colab.research.google.com/github/stared/livelossplot... * https://colab.research.google.com/github/stared/livelossplot...

By @yoz - 4 months
I hope that plenty of developers read this, especially folks on open source projects who don't have dedicated documentation people. There's so much bad documentation out there, and many of these tips are key.

A couple more of my own:

TEST YOUR DOCS

As @codetrotter suggests in another comment, run through your own tutorial with a fresh VM and follow it closely; you'll almost certainly find something to improve.

But this works better if you have someone else try it out instead: get on a video call with them, have them share their screen and speak their thoughts out loud, and most importantly, don't help them. You're trying to find out if they can complete this without additional help. (Yes, it's a usability test.)

BETTER SOFTWARE MAKES SIMPLER TUTORIALS

The article's rule about "let computers evaluate conditional logic" is a good one, but there are multiple places to fix that problem. Sometimes it's in the tutorial, sometimes it's in the software product itself. When the tutorial makes the reader do complex work, it may be a sign that the software has UX issues. You may not be in a position to fix it, but you can probably file an issue.

For the example in the article: could you make the same package name work on all three Debian versions? It'd certainly improve the user experience, and probably make the installation process more resilient.

By @mtlynch - 4 months
Author here.

I've been thinking for a long time about anti-patterns I see when following software tutorials, so I put together this list of things I think differentiate good tutorials from poor ones.

I'm happy to hear any feedback on this list or hear about other things I should include.

By @wiradikusuma - 4 months
For those who can't find other people as your guinea pig, this is the trick I use: After finishing your tutorial, just wait for a few days, and try following it yourself, in a fresh env.

I'm cursed (blessed?) with fish memory so after a few days I forgot everything I wrote.

By @codetrotter - 4 months
> Tutorials often forget to mention some key detail, preventing readers from replicating the author’s process.

I also find this sometimes.

A high quality tutorial on the other hand, is often one where the author bothered to set up a fresh VM and follow their own guide step by step to confirm that everything works as described. This way the author avoids unintentionally forgetting to mention additional dependencies that have to be installed and additional config files that need to be tweaked in order for the steps to work.

By @alentred - 4 months
Extending on the copy-pasteable snippets, another big improvement (flaw to avoid) is to include all imports to the code snippets.
By @jagged-chisel - 4 months
I thought "Keep your code in a working state" would be discussing how to keep code working when some dependency changes. What was covered is valuable advice, but I'd like some exploration on keeping the published code cohesive under refactoring and refinement away from the text.

For example, if I'm P. Shirley and I've written a book (with code) about following light rays between a virtual camera and virtual objects. I have refactored some code to be more clear. Of course, I have iterated on this code to verify it remains correct, but the related text isn't affected. I have to remember where to paste this new code. Unless the documentation had some kind of reference to the specific file, lines, and/or function to render into the text.

What's the advice for best practices here?

By @rinvi - 4 months
Thank you for this. I want to also reference diataxis [0], a systematic approach to technical documentation authoring, which I think has some good advice on the subject of tutorials.

[0] https://diataxis.fr/tutorials/

By @jen20 - 4 months
My pet peeve is code along the lines of:

    if err != nil {
        // handle errors
    }
Or:

    try {
        // something that can fail
    } catch (Exception e) {
        // handle exceptions here
    }
It's usually laziness from the author, but not stating _what types_ of error may occur and how should typically handle them is a plague on documentation and tutorials.
By @ozim - 4 months
A developer who’s new to the React web framework won’t understand terms like “JSX transpilation” or “reconciliation engine.” They probably also won’t understand “SPA,” “soft reload,” or “virtual DOM” unless they’ve worked with other JavaScript frameworks.

Unfortunately if you don’t use that, your beginners will have hard time to believe you are “guru” that they seek. Like if they find other guys tutorial with fancy words they will flock there - looking for some magic trick or some revelation that will hopefully come down on them while reading bunch of hard words without understanding.

Most tutorials are like that for this reason. If you want to teach people author is right - if you are cynical and just want to earn money on a tutorial that’s a different thing. One upside - people quitting “hard” course most likely will be embarrassed to ask for return of money as they would feel it is their fault they did not learn as topic is hard.

If they feel topic was easy and they did not learn, that’s probably guy making tutorial not knowing enough.

My cynical take :)

By @ctkhn - 4 months
Very good stuff. Going to consult this as I build personal and work projects. Working at a huge org right now and its amazing how many crucial details are missed in the tutorials that we have for internal things we depend on
By @baudaux - 4 months
> As soon as possible, show a working demo or screenshot of what the reader will create by the end of your tutorial.

For this reason I am building a new way of writing coding tutorials, with the possibility of writing and running code snippets into the web browser including graphical apps: https://exalib.com

By @rglover - 4 months
This is a great list of stuff. I spent years writing tutorials and wish this list existed when I first started.
By @indentit - 4 months
I really like how clear and well laid out these rules are. It covers lots of things that I have always thought about when I write instructions in README files etc, so it's very nice to see everything neatly described/reasoned in one place. Thanks for sharing!
By @nemetroid - 4 months
I think many of these rules are good, but that there's a too strong focus on ensuring that shell snippets are copy-pasteable without inspection. This comes at the detriment of other considerations, and I think some of the advice goes too far.

Especially so when it comes to the different package names on different Debian versions: what originally was a oneliner is now fifteen lines long with six different branches. What should the reader do if the copy-pasted code fails? How do they know which part failed? What is an "/etc/os-release"? Yes, the happy path becomes simpler, but the reader will struggle to recover from any errors.

By @bandrami - 4 months
Let me add:

Specify up front date and software version. I can't stress this enough.

As the CADT release cycle becomes ubiquitous we're approaching a situation where many tutorials are outdated by the time you finish them.

By @mongol - 4 months
What do you think about writing a tutorial without explaining terminology, but then ask an LLM to generate some kind of terminology index that shows at hover over the terms? If I am writing a tutorial it will take me much longer to explain terminology that I assume is known before. I can see the author's points, but all things considered if I am writing "for free" I don't want to spend unneccessary time. Letting the tutorial be my words, and the terminology index be that of an LLM may be a good balance?
By @javier_e06 - 4 months
I thought that using Makefile targets was the shortest friendliest to show what a project can do. Turns out make and Makefiles can be mysterious when they fail.

Tutorials are "best-effort" and often don't dwell on the rabbit-holes they create when a poor soul runs astray of the sunny path.

Example of a good tutorial:

Python's powerline shell: https://github.com/b-ryan/powerline-shell

The README is succinct. Well put together.

By @ChrisMarshallNY - 4 months
Thanks for posting this.

It’s an excellent example of clear, useful writing, about a topic that could use all the help it can get.

By @taeric - 4 months
If you haven't, I highly recommend taking a look at Knuth's manuals. Even if you are completely uninterested in METAFONT or TeX, they are a delight to read and I would hold both up as a very good aspirational target for software manuals.
By @Linux-Fan - 4 months
I am rather ambivalent about these rules. I disagree with a lot of the individual points, but I am also sure that I have probably often written bad tutorials myself where some of the rules would have clearly helped... :)

> 5. Make code snippets copy/pasteable

I like to use the prompt to identify the language and also the user (root `#` vs. user shell `$`) to perform the action under. I advise against copying random commands off the internet especially those that run as root and may break your system (like `apt` and `--yes` together...). Of course, today, it is often assumed that you have sudo setup and then `sudo ...` is used to indicate the use of root privileges. It is an interesting convention although in my opinion this sometimes hides the actual intent.

I prefer:

    # echo 3 > /proc/sys/vm/drop_caches
over

    echo 3 | sudo tee /proc/sys/vm/drop_caches
The example given in the article is exactly one where attention is required: It adds a PPA as root, thereby giving "full control" to the PPA author. Never straightout copy-paste such stuff.

> 6. Use long versions of command-line flags

I am so much more used to the short versions hence I prefer `grep -RF` over `grep --dereference-recursive --fixed-strings`. Also, my go-to documentation about these commands (POSIX) doesn't even know about the long options.

I know that the advice to prefer the long options is repeated pretty often so it might just be me :)

> 7. Separate user-defined values from reusable logic

Ever followed some "enterprise-grade" software setup tutorial? Sometimes they start by assigning 20 variables to some generic values that you don't change most of the time and then go about to reference them on the next 20 pages or such making it close to impossible to know what is really going on. Also I find that for simple cases this greatly complicates the input process.

I think the example doesn't really show the difference because it has some variables (just not in shell syntax) in the code already like `YOUR-API-TOKEN`. Of course it is better to write `$API_TOKEN` rather than `YOUR-API-TOKEN`. I often prefer to see the example value in the example i.e. not `YOUR-API-TOKEN` but some real string (if feasible). In many cases I won't change a value in the beginning to see how far I get with a “known valid input”. Also, I often prefer to pattern-match some real value against what I have available, e.g. I have a key which I think could be the API key but if the format is totally different from the tutorial I may realize that this is an "app token" rather than "API key" and that I may need to get a different value if it fails to run with my input or such.

> 9. Let computers evaluate conditional logic

If dosed correctly, I think this is good advice. I'd strongly prefer the conditional boxes from the “bad” example over the “good” monster shell script command. In my opinion a tutorial shouldn't optimize for speed of execution but rather foster the understanding by the reader. There is no help if I find this post 10 years later and it helpfully outputs “ERROR: Unsupported platform” on my Debian 16 system. If the text instructions are given as in the “bad” example, I quickly realize that all of this is outdated and I should probably try with the most recent package name (example-package2) rather than meddle with some script.

By @BiteCode_dev - 4 months
Lot of good advice.

I'll nitpick a bit.

You can't tell your user to "echo 'awesomecopter' | sudo tee /etc/hostname" if you may have windows users.

And even for purely linux user, "Good: Give the reader a bash snippet that evaluates conditional logic for them" is quite a scary wall of code for a beginner that as no idea why copy/paste that.

All in all, don't confuse "giving the shortest path to a working solution" and "teaching", which both can be in a tutorial, but they have different goals and you should choose accordingly.

I think the "Teach one thing" is probably the best advice in the article, and too often ignored. I remember as a kid reading Swinnen's book to learn Python and having to understand OOP with his example using ions was a terrible experience.

And if you think "well you should have known that, they teach it in school", you are missing the point.

That being said, writing an excellent tutorial takes a lot of work. Way more than a good-enough one. Choose wisely.

By @egberts1 - 4 months
Look at all the US Army training movies from the 1950s.

Those are near perfect.l tutorial.

By @uvtc - 4 months
A rule I try to follow: don't waste your reader's time.
By @laurentlb - 4 months
A good tutorial should be reviewed and tested by a second person.
By @Fr3dd1 - 4 months
For that topic some nice additional stuff: https://diataxis.fr/
By @chocoboaus2 - 4 months
This is REALLY good.
By @cloogshicer - 4 months
Fantastic article.
By @tdehnke - 4 months
Love it - I'd add to ensure you clearly specify what version numbers you are writing for, and include a date of your writing.

Things change a lot between Version 3 and 6 of something, and something written 5 years ago may no longer apply or be valid today.

By @tolciho - 4 months
> Make code snippets copy/pasteable

Naw, copying and pasting won't develop touch typing nor muscle memory skills. The prompt is sort of a context indicator for the command, as other comments indicate. Also if you're using one of those horrid browsers with CSS support who knows if there are characters that do not display but are included in what is copied. Security risk? Well, you started a chonky browser with a bad security record, so uh additional security risk. Also they probably should be able to type out the commands by hand at the speed of thought, or the commands should be put into a Makefile or script or done via configuration management. Making it easy to copy and paste? Well, if you want to train people to mindlessly copy-n-paste who knows what to who knows where, I guess. Doesn't sound like that would train people to engage deeply with the material. If there's a bigger code example I just put a "=> foo.lisp" link '(this is for Gemini (no, not the Google whatever nonesense (McCarthy invented AI to get money)), the modern web being too much yuck these days) so they can download the whole file.

> Use long versions of command-line flags

What are these? I'm on OpenBSD. More seriously, long flags may or may not help±quick! what does --fake-super for rsync(1) do?—and taking a peek into the manual (another reason I'm on OpenBSD) is sort of a spaced repetition to refresh you on what the flag does, and maybe to scan the list of options to see if anything new jumps out at you (or, at a certain age, what you've forgotten). Close engagement with the material (howeversomuch the learner hates this, as such brain exercise uses up precious energy) is probably a good thing.

(Yes, I know that OpenBSD supports but generally does not document various wacky --from-backside-of-gnu flags.)

> Teach one thing

I am too fond of puns (and have ulterior motives, given the excess of car sitting in America, and the consequent loss of blood to the brain) to apply this in any meaningful way.

By @lsofzz - 4 months
Thank you.
By @edihasaj - 4 months
Great