On commenting code: external vs internal documentation

In my day job, I sometimes have to write scripts in order to automate things that either happen too often to be handled manually or need to be handled in the shortest amount of time possible.But more often, I am tasked with modifying the behavior of an already existing script and/or adding new functionalities.Needless to say, some scripts are way longer than they should be, and they do things that are not supposed to do in a shell-scripting language (think of doing stuff on/to an XML document, using only the Bash shell and tools from the coreutils package). You might think that stuff like that is crazy, and yes, it is a bit crazy but it works and quite frankly, I got to see some rather clever solutions and approaches to unusual shell-scripting problems, and some very creative uses of more or less known features of Bash.

Call it masochism, but I am quite fond of reading code.

Sometimes though, reading scripts is not so pleasant. As shell script is still programming, I see a recurring pattern of poor programming in the form of poor (or non-existant) comments in the code.

I have come to think that code should really be interspersed with two kinds of documentation, and I like to call them “external” and “internal” documentation.

External documentation is supposed to answer the following questions:

what does this script/function do?

what are, if any, its side effects?

what parameters are needed?

can you make an example of the use of this script/function ?

Long story short, external documentation is supposed to help the user of your code use correctly, in particular when using your function the first time. Documenting parameters is particularly important: in dynamic languages like python, the name of a parameter says very little about its type but the type, and in the bash language you don’t even have to list formal parameters: whether you pass two or five of them, they will all be available via their position using variables like $1, $5 and so on.

Internal documentation on the other hand, should really address and describe the internals and the details of the implementation. We could say internal documentation answers the following questions:

how is the problem being approached?

what is the general strategy ?

what’s the meaning/the semantics of the various magic number and magic strings that are in the code?

If you think magic strings are bad, you probably haven’t had the pleasure of writing that many shell scripts. Magic strings are things like utility-specific format strings. Think of the date utility and its many available format strings, or the ps utility (see the “STANDARD FORMAT SPECIFIERS” section in the manpage). Sometimes magic strings can be weird and particular bash syntax.

You don’t see magic strings when you’re writing code because you have just looked it up and it’s obvious to you, but it might not be the case for someone else.

As an example: when formatting a timestamp using the date command, it is a good idea to add a comment with an example output of said format string. Are you writing

date '+%D @ %T'

This is more effective:

date '+%D @ %T' ## 09/02/17 @ 10:20:53

And this is better commenting:

## date: '+%D @ %T' => '09/02/17 @ 10:20:53'

No need to look it up. You can immediately see what generates what.

In the end, as text processing is a significant part of pretty much every system administration task, you can go very far using the standard basic tools from the coreutils package. Once you get to know them, they can be super effective and reasonaby fast for most tasks.

But shell scripting is sometimes underappreciated, and this usually leads to many issue of poor documentation.