What to document?

Background

I am now re-living the joys of documentation with elixir docs and when reading the documentation of mix docs I found this statement:

Documentation is an explicit contract between you and users of your Application Programming Interface (API), be them third-party developers, co-workers, or your future self. Modules and functions must always be documented if they are part of your API.

What does this mean?

So, for example, in my terminal app, the public API (the one visible to the customer) will be the CLI, which already has a helpful documentation. So, now I am done?

Something feels amiss here.

I usually document every module and inside the module I document the public functions. This means all modules are documented, even the ones the user will never see. But now I am having second thoughts.

Question

What is expected of a good documentation of a project?
What parts of the code should I document?

1 Like

More documentation is always better than less IMO. At the very least, you should document the public facing API. Beyond that, I typically do the same with a module doc and docs for all public functions. Sometimes I’ll use comments for private functions to document things for myself later that I don’t necessarily want to be included in the generated docs.

2 Likes

Documentation exists at different layers, with different readers in mind.

  1. outward documentation: Explains to someone how to use your application or library as part of their project. This is in your example the documentation of the CLI so users understand how it can be used.
  2. Maintenance documentation: Explains how it fits together. This is documentation that allows others (including your future self) to understand how to adapt the application to changing future needs.
  3. Code comments: Explains why this approach was chosen, for the situations in which it is not immediately obvious. Examples are explaining what mathematical formula is the basis of numeric constants that would otherwise appear ‘magical’. Or that a certain less-readable implementation was chosen because of performance benefits, etc. Note that the how it works ought to be understandable from the code itself.

For most Elixir applications, (1) is part of e.g. a README or external guide, (2) is written using @doc, @moduledoc and @typedoc (people reading application documentation are the maintainers of the application) and (3) using comments next to the code they talk about.

For most Elixir libraries, (1) is written using @doc/@moduledoc/@typedoc (people reading library documentation are the users of the library) (2) as module- or function-level comments in a module with @moduledoc false and (3) using comments next to the code they talk about.

I disagree with @John-Goff; more documentation does not equal better documentation. On a related note, it takes effort to keep documentation up-to-date with the code; tools like Doctests are great to make this task a bit easier :slight_smile: .

10 Likes

I go a lot of extra miles to make sure my code is self-explanatory – descriptive but short function names, descriptive parameter names, and hopefully giving a hint of the return value. I prefer a @spec to explain the contract of the function. Only if the function does something that cannot be immediately inferred from the spec and the names of it and the parameters, only then do I actually put a @doc.

Documentation is like code: the less of it you have, the less confusion.

4 Likes

It’s interesting to hear different opinions on this topic.

I struggle with the right amount of documentation to include. Mine is mostly a large, boring business application. A good bit of the modules include list_*, new_*, create_*, change_*, update_*, get_*, get_*!, and delete_*. I feel kind of bad about not including documentation for all of these functions, but it doesn’t seem overly useful unless there is something interesting going on in the implementation. It can also clutter the code and can easily get out of sync.

I also prefer a spec, especially if it can be enforced at runtime with typecheck or norm as it is does not get out of sync (assuming there is test coverage) and provides for consistent and clear documentation.

There are certainly cases where documentation is important for explaining the “why” or concepts the developer couldn’t know, but I haven’t felt compelled to add it for a large portion of my app. Maybe I’m doing it wrong.

I would certainly think about this differently for library code though.

1 Like

That’s exactly how I view docs – put them only if there are gotchas and booby traps in your code that would be unexpected for an outsider that has to work with it.

That’s a completely different beast. First you have to make it crystal clear what does your library do and why would the programmer want to use it at all in your README and then you should pretty conservatively document each important piece (and even then not all functions do require docs; but in libraries certainly there are more functions that should be documented compared to internal apps).

1 Like

There’s no right or wrong here OP. Document as much as you can though, seven months later you will be thankful your functions have typespecs and docs with examples.

2 Likes

Given that:

  1. The project I am doing is open source and public
  2. I want people to know how to use it (so it will have a good README)
  3. I want others to read it and understand it

Is there any structure my documentation should aim to have, or can I just go with the default mix docs?

1 Like

I’d say just go with more marketing-oriented material: rationale (what problem does the library solve), the why (should a programmer use it), the 2-3 common scenarios (extremely short snippets demonstrating usage that the most of the users would be interested in) and finally a quick roadmap with checkboxes on what’s done and what still isn’t (and maybe future plans).

2 Likes