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 articleMost 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.
Related
The future of APIs is (still) beginners
The blog post stresses catering to beginners in API design, advocating for inclusivity and user-friendly approaches. It emphasizes clear code examples, parameter names, and seamless API flow for enhanced developer experiences.
Writing Technical Documents Well
Effective technical writing requires clarity, simplicity, and audience awareness. Key strategies include structured storytelling, active voice, and avoiding jargon, ensuring documents remain relevant and impactful over time.
The Modern CLI Renaissance
The resurgence of command line interface tools since 2015 emphasizes user-friendly experiences, clear error messages, and accessible documentation, addressing past shortcomings and evolving with user needs and technology.
What 10k Hours of Coding Taught Me: Don't Ship Fast
The article emphasizes the importance of developer experience and software architecture, advocating for simplicity in coding, prioritizing refactoring, and maintaining code quality through structured practices and passion for the craft.
Yet Another List of Random Opinions on Writing Readable Code and Other Rants
Luca Cavallin emphasizes writing readable code for future developers, advocating for modular design, useful documentation, and balancing business demands with long-term quality to avoid technical debt.
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...
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.
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.
I'm cursed (blessed?) with fish memory so after a few days I forgot everything I wrote.
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.
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?
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.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 :)
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
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.
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.
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.
It’s an excellent example of clear, useful writing, about a topic that could use all the help it can get.
> 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.
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.
Those are near perfect.l tutorial.
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.
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.
Related
The future of APIs is (still) beginners
The blog post stresses catering to beginners in API design, advocating for inclusivity and user-friendly approaches. It emphasizes clear code examples, parameter names, and seamless API flow for enhanced developer experiences.
Writing Technical Documents Well
Effective technical writing requires clarity, simplicity, and audience awareness. Key strategies include structured storytelling, active voice, and avoiding jargon, ensuring documents remain relevant and impactful over time.
The Modern CLI Renaissance
The resurgence of command line interface tools since 2015 emphasizes user-friendly experiences, clear error messages, and accessible documentation, addressing past shortcomings and evolving with user needs and technology.
What 10k Hours of Coding Taught Me: Don't Ship Fast
The article emphasizes the importance of developer experience and software architecture, advocating for simplicity in coding, prioritizing refactoring, and maintaining code quality through structured practices and passion for the craft.
Yet Another List of Random Opinions on Writing Readable Code and Other Rants
Luca Cavallin emphasizes writing readable code for future developers, advocating for modular design, useful documentation, and balancing business demands with long-term quality to avoid technical debt.