Arnt Gulbrandsen
About meAbout this blog

Writing class documentation

A mere ten years after I promised to write this: here's a post describing how to write decent class documentation, for programmers, not writers. This describes how I wrote class documentation for Qt.

This has four parts: Write a sentence-long blurb with the most important thing you can say about the class. Write a few more sentences to give a complete, but rough overview of what the class is (is, not does). Make a list of methods, member variables, enum values and other subordinates of the class, sort the list into aspects, then write about each aspect (but not each member). Finally, make zero or more examples.

Good writers will do it differently, but the goal here is to write something good, not to be a good writer. The best is the enemy of the good.

You don't want to ship crap, and you also don't want to set the requirements so high that only some mythical other people could do the job. So let me digress first into what good means.

Good means that it helps the reader understand your class and how to use it for the reader's purpose. You don't know what that purpose is, but you can guess fairly well, because you are a software developer and familiar with the subject. If anyone can guess well, then it's you.

Sometimes the reader is someone on your own team, working on the same software. In that case the reader will be used to reading and editing the source code. In other cases you're supplying a black box that most readers will use via rubygems, maven/gradle, go get or similar repositories. Those readers never see the source code, they never see the unit tests. When you describe a class in five words or fifty, the description you choose often depends on who you are talking to. That is, the meaning of good depends on the audience.

Both variants of good are well within your capability as a software developer, though. You've done both things verbally, probably many, many times, and you succeeded at getting the point across. Doing it in writing isn't much more difficult.

Back to writing good class documentation:

Parts 1+2: The thirty-second description that'll tell people what this class really is. As for documenting functions, doing this helps you clarify your thinking. Writing a few sentences sentences to give an overview of what the class is improves your own overview.

The simple way to write this is to write a single sentence about the class. A single short sentence, it doesn't have to be complete, it should be simple, understandable and not wrong. Then you look at the sentence, think about what is important and left out, and write each important thing as a single sentence, or maybe as two. This writing style is called the inverted pyramid, and good journalists use it a great deal.

When you write this description, it's best to explain what the class is, rather than what it does. If your phrasing slides towards does, your result often becomes less valuable for the readers, who are focused on what their own code does. A function does, but a class is, and if you keep to is, your description tends to be readable for a wider range of readers with a wider range of use cases.

The detailed description of QWidget is a long example; read the first six paragraphs. The first sentence is the gist, after that each sentence or pair of sentence describes some additional important aspect. By the time you've read all six paragraphs you'll generally know whether QWidget is the class you need to inherit, or what the subclasses have in common.

QPushButton is a shorter example; only three lines of text are enough to describe what that is. The first sentence says what it is. A second, clarifying sentence introduces both of the names readers may have read before. It also suggests the kind of use case for which this is suited, because picking the wrong kind of button is such a common mistake. A third sentence names some good and common examples, in case the reader has used buttons but knows little terminology.

That's it. Three sentences, and the reader has a fair idea about whether this is the right class to use. QWidget needs a great deal more. Both things happen in practice. Most classes are well documented using a three-sentence description, some really need much more.

Of course, as you can see there are more sentences after the three. That's okay, it's not difficult to write, because those are sentences about the details, not about the class. I (or we?) wrote three sentences about this, two or three sentences about that, and both parts were simple because writing three sentences is much simpler than writing a long text.

Part 3: Filling in the right amount of details to tell people how to put this class to use.

The rest of the text about QPushButton is a sequence of short texts about some aspect of the class. We wrote those by making a list of enum values and member function, eliminating duplicates (e.g. accel()/ setAccel()) and sorting the result into a list of aspects. The enum ToggleType isn't an aspect of the class, for example, but the three values of that enum were used to make the list of aspects. Then we wrote approximately one paragraph per aspect, sometimes a little more.

The text looks a little blocky. A trained copy editor can easily see that each paragraph was written mostly on its own. On the other hand, a trained software developer can read this documentation and use the class well.

Part 4: Examples

After that, consider what examples the reader should see. Do not make the mistake we made in the early years of Trolltech, and write code that interests you. Our hello, world eventually morphed into an example of how to make colourful animated letters jump around the screen. Fine and impressive, but not helpful for a reader that looks for how to write a first hello, world.

What you should do is look at the documentation you've written, and if the class merits an example at all, you decide what example the reader would ask you for, and write that precise example.

QPushButton contains an excellent single-line example. (You may have noticed that even though it was written at the end, we moved it up to nearly the start of the text.)

QWidget is used by many example programs, so it contains a three-sentence description of one example program, explaining why that that particular example is good to start with.

QPushButton also contains automatically generated links to complete example programs that use it; our documentation tool (qdoc) generated those. In my opinion, each of those example programs should have a declared audience and goal. You should make clear (in a comment in each example program) both what this example program is supposed to teach and who should learn from it. We didn't at Trolltech, which harmed both the example programs and us as team.

After that: Editing helps. Editing, in this case, mostly means moving the blocks around. You can see that we moved the example in QPushButton near the top. That just looked right. Looking at QWidget, you can see that the events are grouped. I wrote the text for each group independently, then we looked at it and decided that the exposition worked best if the descriptions were ordered in that order.

Real editors do more, of course. This posting is about writing well enough to enable software developers to use a class well, not about writing better than that.

After that: Refining the documentation due to FAQs helps. When we answered support questions, when we answered FAQs, anything, we'd try to edit something a little to make that FAQ go away. That's why the QPushButton text points to the other kinds of buttons (people have terrible problems deciding whether a tool button, command button or radio button is the best for a given case, and so on), and it's why the QWidget text mentions top-level widgets so prominently.

This posting hardly mentions tools. Good documentation benefits from good tooling, but not all parts equally. The subject of this posting is text that has to come from a someone's mind. Other parts can come from analysing e.g. relationships in the source code.

Some tools aim at producing the best possible result from whatever effort you put in. That's not what I write about. My goal is strictly to produce usable results with as little human effort as possible.

The links above point to a very old version of Qt. Later versions are perhaps better documented, but for this posting I thought it suitable to use a version written by software developers rather than by technical writers. The users praised it. People like you can write documentation that users praise.

Using letsencrypt certificates with archiveopteryx

That works, there's no problem at all. For a while. But aox reads certificates on startup, and is stable enough to run for months or years, longer than the lifetime of a letsencrypt certificate, so eventually it will use an expired certificate because it hasn't reread its configuration in the past three months.

I found a really nice unixy solution in incron, a linux-specific cron-like daemon that watches directories and runs programs when things happen in those directories. It's small, self-contained and easily debuggable, in the best unix tradition. Charming.

I installed incron using apt-get install incron and added a one-line file as /etc/incron.d/aox-restart: /etc/letsencrypt/live IN_CREATE /usr/local/archiveopteryx/bin/aox restart. I think it's probably best to watch the file the aox tls-certificate variable specifies, but I started with the entire …/live directory for ease of testing. That let me touch a file and see aox restart.

Now aox restarts instantly whenever certbot renews the TLS certificate.

It would be possible to leave existing IMAP connections running, but frankly I don't think that's worth the effort.

On being right

My favourite Stack Overflow answer is for a deleted question. The question was off-topic by the site's rules, which steer away from opinions and possible controversy and towards the purely factual, so deleting it was right. But.

The question (this one, visible only if you have ten thousand internet points) was what real life good habits has programming given you? and the answer I so appreciate was by Robert Rossney, who wrote:

I no longer equate thinking I'm right about something with actually being right about it.

It's now very easy for me to entertain the thought that I may be wrong even when I feel pretty strongly that I'm right. Even if I've been quite forceful about something I believe, I'm able to back down very quickly in the face of contradicting evidence. I have no embarrassment about admitting that I was wrong about something.

That all came from decades of working in a discipline that mercilessly proves you to be mistaken a dozen times a day, but that also requires you to believe you're right if you're going to make any progress at all.

How to use Plusxome

Plusxome is a rewrite of loathxsome, which in turn is a rewrite of blosxom, which also spawned other rewrites, of which pybloxsom is/was the best known. The original purpose of my rewrite was to play around with C++11. I appear to have been running it in production for many years now, which implies that it's solid enough to warrant a user guide. The number of likely users suggests that a very short one is sufficient. But one should exist, because I do not approve of undocumented software.

Plusxome is the kind of program that's user-friendly and choosy about who its users are. This program is only for people who host their own blogs on linux, are happy compiling C++ and can write HTML.

First, git clone the source and build it. Second, write a template, or several. One of my templates is quoted below. Third, write some HTML that'll turn into a blog posting. Again, an example is below. […More…]

Jelly 2

The Unihertz Jelly was small and fine, and I did like it but I had to give it up. The battery wasn't good enough for my use when travelling, and now that my eyes are fifty years old I admit I found the screen too small.

At the time I wrote that a smartphone should be small and light, have a large screen and battery, be fast enough, and not have too many bugs. Obviously there's a conflict between overall size and screen/­battery size. Now that Unihertz has shipped a slightly larger Jelly 2 I decided to buy one to try (after worrying for a while about whether the screen was a large enough part of the phone's front). I've used it for a while now.

The phone isn't elegant, chic, stylish or pretty. I want it to stay in my pocket, out of sight, so logically speaking I shouldn't mind its looks. I really shouldn't. On the other hand, it's well-built and feels solid. It lies well in the hand.

There's a visible Torx screw (that does nothing?).

The apps I want to run work, even though they clearly are designed for bigger screens. The battery and screen are OK. A very small screen is a very small strain on the battery, but the screen is big enough for my eyes and I can enter text.

Like its predecessor, the Jelly 2 is not fun. That's a good thing in my opinion. This phone can be used to call, it can speak in my ear and tell me to turn right at the next intersection, it can be used for 2FA and my other apps, and it isn't a timewaste magnet. Browsing Instagram, Twitter and so on is possible, but that kind of thing isn't attractive on this phone's display. This is perhaps one reason that I don't worry about the battery. I charge it I notice it's low and don't worry. If I charge it in the morning, I always have >50% battery left in the evening.

It fits in every pocket I have, even in my tightest jeans, it runs the apps I need, and if it makes me spend less time on Twitter, that's fine.

My office suffers from COVID-19

I have a purpose-built office at home. We bought the neighbouring apartment and I cancelled the lease on my former office. So in the morning, after my 60cm morning commute, I sit down to work, and then…

Ten minutes pass, or twenty, I start to focus. One child interrupts. I help with whatever. I try again, half an hour passes. Another interruption — a child perhaps, or my wife wants to discuss food for next week or wonders whether it's time for an espresso, or the DHL chap who knows very well that I'm there and can pass parcels to the neighbours. Hi Arnt he says, I have a parcel for a <name>, can you…? Later the neighbour will ring the doorbell too, but that's usually after the end of my working day. Usually.

After the third interruption it's really difficult to gain focus at all. The corona virus has turned my lovely office into almost a regular one.

Intent ≠ effect, again

Github and others have renamed the main git branch to main from the old name master. I don't care one way or the other, it's just a symbol and I don't see that this symbol affects anything. The Americans have renamed their dark-skinned fellow citizens every decade or two since I was born, to little effect so far. I don't see any reason why renaming master to main will have more effect. On the other hand I don't mind that branch being called main either. On the third hand, someone has surveyed other people's response and got interesting responses.

I quote: Something I was not expecting when gathering the data for this survey is that every single African American who answered the survey responded No in support of the change. Not only that, when asked to explain their reasoning, all of them sounded fairly spiteful towards Github and its executives, since they felt that these decisions were made by white executives who didn't actually consider whether it offended them or not, …

Interesting point. Arguably, Github wishes to avoid offensive terminology, so it renames without consulting the people it wishes to not offend, which is an inconsiderate way to avoid offense, if that survey is even nearly representative.

The intention of Github's action is clear (and positive), the negative reactions wouldn't be difficult to find by asking a focus group, and what's the positive effect again? A software development company shouldn't let positive intentions win over foreseeable negative effects. Serving users demands humility, and specifically it means caring much, much more about what the users think than about one's own good intentions.