How NOT to write user-friendly documentation

Warning: This is essentially a long rant about the built-in help of git, but with specific problems pointed out and some constructive suggestions buried at the very end.

When I was starting on my PhD in mathematics, there was a time I remember where the professor in one of my classes referred to a problem on our homework assignment as “a calculus problem.” Later during the week, the six or so students in the small class were talking about the homework and one of the brighter students (i.e. not me) trepidly asked, “Did he really call that a calculus problem?” It turns out we were all stumped by the problem, and we were surprised–and scared–that the professor utterly trivialized it. We did all eventually solve the problem, and did ultimately agree that it was a generalization of ideas from calculus, but not until after getting a bit of a scare that we were in over our heads in graduate school.

In a similar way, Carl and others have argued that they just don’t see the big user-visible differences in the models offered by git and other VCSes. Many a git user seems to have had trouble understanding why other systems would be marketed as being easier than git. I am a lot slower than most of them, but I eventually figured it out and I do think that git could be just as easy if tweaked appropriately; however, it sure does seem to place every obstacle possible in the way of users discovering that.

This blog post is dedicated to what I believe is the single biggest obstacle in the way of users learning git: its built-in documentation (which doubles as its manpages, or vice-versa). Let me first point out that the git manpages are stellar from the point of view of comprehensiveness, or from the point of view of those writing their own UI for git. However, in this post I will judge these documents based on their friendliness to users who are new to git (which may not have been one of their design goals for those pages, so such judgement may come across as unfair).

Do not layer concepts — make it all or nothing

Imagine taking a computer user who is bright but unfamiliar with unix or common editors associated with unix, and giving them vi (or vim) to run. Also, imagine making them unable to use vi until they understand every feature and capability of it. Without a way to incrementally improve their productivity (better manuals, or a friend to explain things, etc.), most users will either give up or take an extremely long time to become productive. While this analogy is a bit of a stretch, for the most part this is precisely the way the git manpages are structured[1].

I’ll take push and pull as an example. If you take a look at git’s help for push or pull (or fetch), you’ll note that “refspecs” are featured prominently. Embedded in the explanation of refspecs, you’ll find concepts, terms, and other details such as rebasing, octopus, configuration file syntax and effects of such configuration options, fast-forwarding, nonlinear history, repository storage format, implementation details about git’s repository directory layout, local and remote repositories, remote tracking branches, and merge strategies–all inextricably intertwined (or so you’d think on your first 12 readings). refspecs pack a lot of information into a short amount of space, making them very convenient to the expert; but for new users this just places a mountain in front of them getting started. Since push and pull are the methods of collaborating with other users and refspecs are necessary to their functioning, new users often feel stuck.

In a similar way, when I was starting I thought that I would have to understand the index, reflogs, tree-ish’es, internal repository storage format, and a few other arcane things before I’d ever be able to do anything productive with git diff.

Assume that all details are equally useful

This section could likely be combined with the previous one, but I thought it was worth a special mention. It typically comes across as “this document is overloaded with detail”, though the existence of details is not necessarily the problem (you can have a comprehensive document and have it be understandable; take a look at the cvs, svn, or hg books at red-bean.com). The problem with documentation that assumes all details are equally useful (typically a subconscious assumption) is that it makes it extremely hard for the user to get started. git’s commands have boatloads of flags, and with few exceptions there is not much guidance at all about which are more important for just getting started. Users have to sift through it all and try to figure it out themselves.

The manpages also often specify details before concepts, erring as far as possible on the side of precision. For example, take the opening sentence of the description of the git diff command: “Show changes between two trees, a tree and the working tree, a tree and the index file, or the index file and the working tree.” After reading this, the user can only respond with comments like: “What’s the index file?” (or maybe even “is the ‘index file’ something slightly different than the ‘index’ I read about elsewhere, perhaps just a subset of it or how it behaves?”), “The working tree isn’t a tree?!?”, or, perhaps most likely, “Huh, what?” The git diff help tries, starting from the beginning, to introduce as many concepts as possible (without explanations) and just befuddles the user. For another example, take a look at the description of git checkout. For someone familiar with git, they won’t see anything wrong. In fact, I don’t see anything hard there anymore. However, do you know how many dozen times I tried to parse those two short paragraphs in attempting to learn git? I don’t — I long since lost count.

Require understanding of deeply nested commands

The documentation in git often defers explanation by referring to other (low-level) commands, in a way that makes users feel they have to understand all the low-level commands too.

Here’s an example. From the git push documentation:

The <src> side can be an arbitrary “SHA1 expression” that can be used as an argument to git-cat-file -t.

From the git-cat-file documentation, explaining the -t option:

Instead of the content, show the object type identified by <object>.

Finding the definition of <object> on the git-cat-file page:

The name of the object to show. For a more complete list of ways to spell object names, see “SPECIFYING REVISIONS” section in git-rev-parse

(More complete?!? There was no explanation here at all!) And for kicks, the very beginning of the SPECIFYING REVISIONS section of git-rev-parse:

A revision parameter typically, but not necessarily, names a commit object. They use what is called an extended SHA1 syntax. Here are various ways to spell object names. The ones listed near the end of this list are to name trees and blobs contained in a commit.

If the user gets to this point they are like to ask whether the object from the git-cat-file page refers to a commit object, a different kind of object, or a more general case that includes both. Also, they may ask, if it’s just a commit object, then part of the ensuing explanation is going to be for something else other than what we are interested in…but are we going to be able to differentiate which parts of the explanation that is?

Here are some other examples, all of them taken from the the first paragraph or two of the descriptions of each command. From git-checkout: “It updates the named paths in the working tree from the index file (i.e. it runs git-checkout-index -f -u)” (one has to love following up an unintelligible (to new users) explanation by referring to a lower-level command that assumes the user knows even more). From git-bisect: “This command uses git-rev-list –bisect option to drive the binary search…“. From git-log: “The command takes options applicable to the git-rev-list command to control what is shown and how, and options applicable to the git-diff-tree commands to control how the changes each commit introduce[d] are shown.”

Prefer implementational details to user-level concepts

Just one example I know of immediately…open up the git-checkout manpage and you’ll see a section titled “Detached Head”; it’s completely meaningless to new users. Trying to describe the concepts (“working with no active branch”, “working on an unnamed branch”?) would be much better. I think they’ve tried to stomp out issues in this category, so there are not as many as there used to be.

Make your terminology inconsistent

I’ll jump straight to a quick example from git: You put things in the “index” with “add” which is known as “staging”, you remove them with “reset” (or “rm –cached” if it’s the initial commit), you use flags like “–cached” to refer to index stuff in some places, use “HEAD” to avoid it (specifically in diff), and sometimes the flags related to it are “soft” vs “mixed” (which also need to be juggled with “hard” in git-reset). While users eventually learn all the synonyms and related terminology, it really slows learning down.

Use inconsistent conventions

The git manpages do not use consistent conventions. For example, taking a look at the synopsis lines you’ll see “<filepattern>” on git-add, “file” on git-annotate, and “-pNUM” on git-apply; why are non-literal items denoted with angle brackets in one case, uppercase in another, and no special markings in a third case? On the git-push manpage alone, you’ll see “–receive-pack=<git-receive-pack>” and also “–repo=all”; angle brackets in one case, and plain text in another? On the git-diff manpage you’ll see “<commit>{0,2}” and also “<path>…”, while on git-bundle you’ll see “refname…”, and on git-checkout-index you’ll see “[<file>]*”; so denoting more than one item is done with a variety of regexes, an ellipsis combined with angle brackets, or just a plain ellipsis.

The more ways you have of referring to things, the more likely users are to confuse them. One that bit me particularly hard was the “<commit>{0,2}” in the git-diff synopsis. Now, I use regular expressions daily and my usage of them spans emacs, grep, sed, perl, python, and probably other places I’m forgetting…but it still did not occur to me that this syntax in this context happened to be a regex. It looked somewhat similar to reflog notation in git, and I launched into all sorts of reading up on reflogs (and the documentation it depended on) trying to understand this detail. I also read the online tutorial, parts of the git user manual, blog sites, and even mailing list archives. I gave up and moved on, but never felt comfortable that I understood things…until months later when it dawned on me that this was a simple regex.

What can be done to fix this?

Well…some people have fled to hg and bzr to avoid these problems in git. As far as built-in documentation, both of them have done well and have very nice documentation for new users; bzr’s is particularly well polished. Adopting one of those systems is a reasonable choice which I can’t fault people for making.

Now, I dislike reaming a project without mentioning something good or at least providing constructive feedback. In addition to spelling out some specific problems throughout this post, I came up with some constructive ideas for improvement: Easy GIT, a brainstorming session about making git more user-friendly, in the form of a usable demonstration. It also doubles as a transition tool, helping users switch from other systems (particularly svn). I don’t know if anyone wants to adopt any of my ideas or documentation, but it’s out there for people to evaluate (even if not yet complete).

I will also note that Govind Salinas had a similar idea and created pyrite (and did so before I started eg, though I didn’t learn of it until after I was using eg daily). So it seems that I am not the only one thinking along these lines…

[1] The online tutorial and user manual of git are different, but sadly users don’t want to read big long tutorials when they are already familiar with another “similar” system; rather they just use ‘git help’ and get the git manpages…and end up more confused than they started.

This entry was posted on Saturday, March 15th, 2008 at 1:41 pm and is filed under General. You can follow any responses to this entry through the RSS 2.0 feed.
Both comments and pings are currently closed.

19 Responses to “How NOT to write user-friendly documentation”

I think you’re making the classic mistake of assuming that the manpages are there for learning how to use a system. This really isn’t the case. I for one mainly use manpages to look up command line options. The assumption that manpages are supposed to be actual manuals is what lead to GNU using info – and frankly, it sucks. man is better in the majority of cases, because it lets me quickly see the syntax of the command and look up command line options.

If you have something simple enough, like the Unix cp command, a manpage is enough – you can fit the full description of its operation into a few pages. But a system like git is inherently complicated enough that you can never really expect to fit a full description within a manpage AND be newbie-friendly. In this case, it’s better to do what the git people have done – use manpages to document the syntax and command line options, but have a separate tutorial for newbies.

The way to create sane documentation as well as UI’s is to consider use-cases.

My use-case for RCS’es is: reasonably bright graduate student shows up at the lab for a six-month project. He or she has some programming experience but Comp Sci is not their major and they are not deeply versed in the Unix world.

They’ll get their own account so that they can work in their own tree of the software system without breakign everythign for everybody, and they’ll be able to update their own tree with other checked in changes as time goes by. When their own six-month project starts shaping up, they’ll be merging their new stuff with the trunk.

Now, they have perhaps six months total for their project, and that includes figuring out the current code base, read up on the state of the art and prune their ideas to fit reality. They do _not_ have the time nor inclination to spend a week (to say nothing of several weeks) just figuring out the revision control system, and it would be impossible to require it. The documentation needs to take a person like that from zero to checking out the codebase, branch it, do work on their private copy (adding and removing files), check in their changes and check out and merge with trunk changes, all in a brief and to the point enough way to be understandable and followed by the new user as they are working on their project.

A tool that doesn’t have documentation like that, or worse, that _can’t_ have documentation like that, is not going to be adopted widely; not by us, and not by most other code control users.

“I think you’re making the classic mistake of assuming that the manpages are
there for learning how to use a system. This really isn’t the case. I for one mainly
use manpages to look up command line options.”

Actually, I totally agree with you and you simply missed it. What you seem to be missing is that you assume that since the git manpages are manpages, that they fall solely under the reference documentation category rather than tutorial documentation category. That would be true if git had a tutorial-oriented built-in help system, but git reuses their manpages for that purpose instead. Take a look at Easy GIT; I provide a built-in help system…and then refer the user to the git manpages for comprehensive documentation.

However, even considered as reference documentation, the git manpages still need a lot of cleaning up.

Colin: Huh? You seem to be assuming “newbie” in this context means new to linux/unix/etc with no development background. I’m not sure why that is, but I merely meant it as “new to git” (and specifically had in mind people very familiar with linux and VCSes other than git). Hmm…maybe I should change the title…

pclouds: Yes I need to do that…among a number of other things. And yes, the user manual does make things much clearer, but (1) it didn’t clear up my confusion caused by the git-diff manpage (and users will still refer to such pages even if they’ve read the manual, simple to get a brief referesher…and when they do so they’ll find several unpleasant surprises lurking), and (2) If you’re expecting users to read an entire manual before getting started then you’ve lost. (See Janne’s comment right after yours.)

Janne: In regards to
“A tool that doesn’t have documentation like that, or worse, that _can’t_ have
documentation like that, is not going to be adopted widely; not by us, and not by
most other code control users.”
I completely agree with the sentiment, but I disagree with the implicit assumption that git is a tool that can’t have documentation like that. Well, in its current state with no UI changes I would agree, but the number of changes needed to make git into such a tool are smaller and more minor than I think most people would realize.

I’ve often encountered free software documentation that is nearly impenetrable, because the author is a total geek about some technical area and thinks that only fellow geeks, those who understand the software implementation from top to bottom, are worthy to use the system.

The first time I encountered this in a big way was with ntpd. I just wanted my machine to keep the correct time. But ntpd’s documentation was written by ntpd’s main author, and the guy is a total time geek, a world expert on ways to keep distributed computers’ clocks in synchrony under every possible circumstance, and he wants you to understand everything about this too before you dare to configure ntpd. The simple cases are mixed together with the hard cases, and no recommendations for beginners were given. This was in the 90s; the docs have gotten a little better than this, but only a little.

Evidently sysadmins of Unix systems of the day didn’t understand this either, and they just copied each others’ config files, treating them as a black art.
Today, the distros solve this for us, and ntpd has been changed to have more reasonable defaults, so everyone doesn’t have a massive, complex config file.

Eliah, sorry; I didn’t really mean to imply that git would be incapable of being straightforward to describe. I realize my last sentence comes off that way. There are plenty of software systems (not thinking just of revision control) that really are too complex, however. No matter how good, and no matter how they simplify your life once you know them, the effort needed to learn them and teach them in the first place precludes them for use in many situations.

I keep wondering, as I see people struggle with the idea of revision control, if the tools are not a bit too reflecting of the internal mechanisms. Transparency is often good, but this may be one instance where hiding the reality and present a different, more easily graspable, metaphor may be a better solution, UI wise.

I have discovered this on Easy Git after figuring quite a lot of times how to easily do it. How it’s this supposed to be done with plain git???

I love the git checkout for changing between branches, but I hate that uncommited changes are brought all the way. With stash I could put them someplace while doing some fixes on a diferent branch, and later came back. Nice!

@bisho: in plain git, its ‘git stash’ This is an excellent point about the discoverability of git.

@elijah: Brilliant analysis of the discoverability problems of git EasyGit is looking great and has a cool name as well (though the contraction can get a bit confusing in a sentence, as i just discovered…). You rock!

I see… I was really digging in git help for this, but I was unable to find it on checkout manpage or on the tutorials. I fill stupid, hehe. Not being english native also makes things harder.

When I see this on eg help I see the light:

Time saving commands
eg bisect Find the change that introduced a bug by binary search
eg stash Save and revert local changes, or apply stashed changes

One more thing:
Do you know if there is something to select which changes we like to commit on one file. Some times I found two unrelated fixes and I want to commit them separately to get clear log. I usually do this by generating a diff, reseting the file, splitting the diff in two files with the different changes and applying them one, commit, second, commit. With stash I will avoid many of this problems, but it will be helpful on some circumstances.

bisho: Selectively committing hunks is something you can do a couple different ways.
1) You can use ‘eg commit –interactive’
2) You can stage your changes as you make them (See my in-progress http://www.gnome.org/~newren/eg/git-for-svn-users.html, in the staging changes section) and commit just the staged changes.
3) You can use ‘eg add -p’ (or even ‘eg add –interactive’) to selectively stage hunks, and then commit just the staged hunks.

When trying to do documentation, it pays to remember Donald Knuth’s comment:

A […] noteworthy characteristic of this manual is
that it doesn’t tell the truth. When certain
concepts […] are introduced informally, general
rules will be stated; afterwards you will find that
the rules aren’t strictly true. [….] Once you
understand a simple but false rule, it will not be
hard to supplement that rule with its exceptions.

Terry: I think Knuth’s documentation concept has a point. But this reminds me a personal anecdote: I remember that it was just that tutorial principle which drove me up the walls when I was reading Karl Marx’s “Kapital”. He started with introducing very simple, basic ideas and claims, and it was quite obvious to me that these couldn’t be true as stated. To be honest, I got angry about his flawed logic, just to find him fixing its defects and “telling the reader the truth” many, many pages later.