docs by code and comments
Let's think about it
... cause' that might be all we need.
We tend to produce a couple different types of documentation:
- Tutorials - for quick start, learning by example
- How To Guides - goal oriented, solving a specific issue in a series of steps
- Explanation - helping to understand concepts, context, background, overall architecture and how things work and why
- Reference - information index, accurate and complete
Each of those documentation types is provided in slightly different way using different tools and formats: reference docs are typically auto-generated from code; tutorials are written by hand with a lot of pictures and are typically quite long (even might be a video); how to guides/examples are typically mostly code with one paragraph telling what the code does; and explanation docs read like a book.
All of that requires a lot of work and effort to keep up to date. But as I'm thinking about it the code and comments might be all we need to satisfy all those needs.
Tutorials
Tutorials are just long examples which have to be assembled by the user, which makes them actually less accessible, slower and more time consuming. In my opinion example projects (yes, entire, separate, premade, working projects) are superior and provide more value.
Instead of forcing the user to assemble working project step by step by themselves let's just give them working example project with numbered comments. That way they can play with already working solution or if they have time to assemble their own they can fallow the comments and can already see the expected outcome.
The only advantage tutorials have is forcing the reader to do the work which might be more educational. The premade projects will not benefit lazy people as much, but provide more value for those who are in hurry or just want a boilerplate head start.
These are also easier to keep up to date as you can just verify if they work by compiling and running test. If API changes the compiler will tell you to update the tutorial project. That's something which you don't have with just a wall of tutorial text articles and screenshots.
How To Guides
Basically the same thing as a tutorial but shorter. Those already tend to be code snippets with comments.
Just make sure that they are shipped in the repo packaged into some sort of project which can be compiled, run, and tested so you know when they break and need updating. Also so the user have easier time to experiment with them.
Explanation
The only one which cannot be expressed with code. But in my opinion creating an entire system just to produce separate documents is a waste of time. Programmers work with code and are comfortable the most inside their IDEs and text editors. So why not ship the concept explanation as a simple text files or just a header comment.
We have a nice example of that in the
stb libraries.
Just open any .h
file from this repo like
stb_ds.h
and see the top most comment.
In most cases that's all we need. It has an obvious disadvantage as you cannot use pictures in your explanation. That might be useful for showing graphs and diagram so a simple markup language like html or markdown might be used.
By the way, if you think that html is not simple just look at the source of
this page (CTRL+U
on most browsers). Such html pages can be
viewed efficiently both in text editors and browsers.
Reference
I quite dislike the auto-generated reference docs for APIs. They always miss some crucial information which can be find only in the source code or are just hard to navigate through. I much more prefer a well structured source code with comments.
Here we have a real word example - a Microsoft C# documentation for one
of the most basic classes:
String
.
C# is a typed language and the method return type is quite important but it's
one thing you will not see in the automatically generated docs. You have to
click on each individual method to see the return type.
Java does much better job with that
(String
)
but as you can see this document shows you exactly the same amount of
information as you can see by looking at the code. If your code editor
supports symbol navigation then you are even better off with just the
source because you can not only jump across definitions and read the
documentation comments but you can also look for usages of given type
in other places.
The plain text docs also can be easily searched through with the tools you already familiar with not relying on docs search implementation.
I have more to add
So in summary all you need is code and comments. There is not need to generate some kind of documents from those as it makes them only less readable and accessible. The real, working example projects have also the advantage of being easier to maintain. Some languages out there already pivot towards that kind of documentation - Emacs Lisp, Common Lisp, Zig, Go.
But lately I had a discussion with other programmer
🐢
if the common way of writing comments above each API function is necessary and
good. It's tedious to write the documentation comment above each of the
API/public function. There is typically a lot of repetition especially for the
parameters. Let's have an example
(Parser.cs
):
/// <summary> /// Removes empty lines from the given linesQueue until the first non /// empty line is found. The first found non empty line is not removed /// from the queue and stays there to be used. /// </summary> /// <param name="linesQueue">queue with lines from packages description file</param> void MoveToTheFirstNonEmptyLine(Queue<string> linesQueue) {...} /// <summary> /// Parses chunk of data with packages to install. /// </summary> /// <param name="linesQueue">queue with lines from packages description file</param> /// <exception cref="FormatException">thrown when format is invalid</exception> Package[] ParsePackagesToInstall(Queue<string> linesQueue) {...} /// <summary> /// Parses chunk of data with packages dependencies. /// </summary> /// <param name="linesQueue">queue with lines from packages description file</param> /// <exception cref="FormatException">thrown when format is invalid</exception> PackageDependency[] ParsePackagesDependencies(Queue<string> linesQueue) {...} /// <summary> /// Tries to get next chunk of data as list of Packages arrays. /// First line should contain number representing chunk size. /// Then each next line is converted into array of Packages and yielded. /// </summary> /// <param name="linesQueue">queue with lines from packages description file</param> /// <exception cref="FormatException">thrown when format is invalid</exception> IEnumerable<Package[]> ParseNextPackagesChunk(Queue<string> linesQueue) {...} /// <summary> /// Extracts Packages objects from given string. /// </summary> /// <param name="packagesString">one string describing packages</param> /// <exception cref="FormatException">thrown when format is invalid</exception> Package[] ParsePackages(string packagesString)
We can see that most methods have similar parameters and similar exceptions. That's typically the case with API/public functions. Those comments also have special XML tags to generate reference documentation.
So let's experiment. Wouldn't it be better if we would simplify that a bit and write just one common comment for those methods:
/// Methods accept linesQueue collection with lines from packages /// description file and pops lines as they are being processes. /// FormatException is thrown when format is invalid. void SkipEmptyLines(Queue<string> linesQueue) {...} Package[] ParsePackagesToInstallSection(Queue<string> linesQueue) {...} PackageDependency[] ParsePackagesDependenciesSection(Queue<string> linesQueue) {...} /// Tries to get next chunk of data as list of Packages arrays. /// First line should contain number representing chunk size. /// Then each next line is converted into array of Packages and yielded. IEnumerable<Package[]> ParseNextPackagesChunk(Queue<string> linesQueue) {...} Package[] ParsePackages(string line) {...}
This version has half the lines and is both easier to read and maintain. There are no duplications and less text in general. It also forces the methods and parameter names to be more correct and better express what they represent.
When parameters are obvious or well explained there is not that much to
document about the functions themselves. Especially if you group them.
Here is a nice example from
suckless dwm:
drw.h
Finishing note on self documenting code
It's not possible.
Code expresses how the work is done, but not:
- why it is done this way
- what other methods have been tried
- history of changes
- explanation of optimization
- todos ;)
So besides comments used for documentation it's a good idea to sparkle some around your code to not only explain what is happening but also why.