Best practice for documenting crates (README.md vs documentation comments)

As a little exercise while learning Rust, I wrote a simple program for converting images into ASCII art (GitHub - dfilaretti/img2ascii_rust: Command-line image to ASCII art generator written in Rust).

Now, I read on the book that it's possible to write crate-level documentation using //! comments so that it will appear at the top level when generating documentation via cargo doc.

I was also wondering (for projects hosted e.g. on GitHub) how to keep that information in sync with the usual README.md and found that it's possible to indicate readme = "README.md" in cargo.toml so that when uploaded the documentation to display on the web page will be read from README.md.

So my doubt is: if my project is hosted on GitHub (or similar) and has a README.md, should I still include crate documentation (via //!) in my code or should I avoid that completely (assuming the README.md covers the same information)? (the scenario I have in mind is including a big block of //! comments at the beginning of my source file explaining what the program does and how to use it, a bit like a README would do).

You can use #![doc = include_str!("../README.md")] to keep readme and crate-level docs in sync.

2 Likes

In my opinion, writing substantial doc comments[1] makes sense primarily for libraries which you publish and intend for others to use. For executable programs, only write as much as is useful for people (yourself or others) intending to make changes to the source code.

When documenting a library, the principle I follow as to what goes where is:

  • The README.md should explain when and why to use the library. What does it do? What are its benefits? What are its requirements? Is it a port or a fork of another library?
  • The crate documentation should explain how to use the library. What are the core concepts? What types and functions do I use first?

These have substantial overlap — for example, a short code example might make sense in both places — but they are different.


Additionally, the same text cannot serve both purposes well for technical reasons. In particular, the crate documentation should contain intra-doc links (e.g. “to start a new game, call [`Board::default()`] to obtain a [`Board`] in the normal starting position”) but those same links will not work in a README file. (You can add explicit URLs, but if you do that, you're making an assumption about docs.rs or wherever your documentation lives, and making your documentation less usable for offline use and development.)

So, for libraries, where good documentation matters, I recommend not using #![doc = include_str!("../README.md")], because making the text the same forces it to serve two purposes and be worse at both.


  1. which, technically, are not comments, but an actual part of the syntax tree ↩ī¸Ž

4 Likes

README.md is for when people are on the web, github, or crates.io, for example. README.md can have images rendered. Also a README.md is good for developers to read about the library or program and could contain meta-details...why the code was written, links to webpage, repository, crates.io, FAQ, ect.

The //! comments at the beginning of your lib.rs file are for the library documentation. Stuff that will be read when someone does

cargo doc --open

The lib.rs comments are meant to be read 'inline' when looking at the source code. They could contain more details of how to use the code.

1 Like