Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API documentation front page styleguide #1687

Closed
wants to merge 26 commits into from
Closed
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift click to select a range
c43e66a
Add API documentation front page styleguide
Jul 25, 2016
5c84df4
Update formatting (thanks vim)
Jul 25, 2016
09b551e
More formatting updates
Jul 25, 2016
d94849b
Cleans up links and formatting.
peschkaj Aug 19, 2016
b4ff67a
Merge pull request #1 from peschkaj/front_page_styleguide
Aug 19, 2016
74c84e9
How we teach front page documentation
dtolnay May 7, 2017
14b424d
Clean up trailing whitespace
dtolnay May 7, 2017
5e7544d
Mention readme in the summary
dtolnay May 8, 2017
4754fdd
Tie this to 2017 roadmap
dtolnay May 8, 2017
f278e48
Fold examples under each capability
dtolnay May 8, 2017
0192c10
Brainstorm some alternatives and open questions
dtolnay May 8, 2017
565d2c1
Where to put license boilerplate
dtolnay May 8, 2017
87f3972
Where to explain getting help
dtolnay May 8, 2017
ec3e74f
Rewrap consistently
dtolnay May 8, 2017
8793929
Factor links out of the paragraphs
dtolnay May 8, 2017
6d6c1a8
Rethink the purpose of the introduction
dtolnay May 8, 2017
3e5662b
Multi crate guidance
dtolnay May 8, 2017
7b0bd87
Example budget
dtolnay May 8, 2017
feb4972
Migration notes
dtolnay May 8, 2017
0cb8cca
Crystalize the purpose of the first example
dtolnay May 8, 2017
8b54517
Preserve backticks in the original
dtolnay May 8, 2017
8636aeb
This example prints to stdout as a side effect
dtolnay May 8, 2017
509a323
Wording
dtolnay May 8, 2017
708f120
Smaller headings in the quoted text
dtolnay May 8, 2017
7348e61
Readme unresolved question
dtolnay May 8, 2017
4cce1e2
Where to put capability examples
dtolnay May 8, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
372 changes: 372 additions & 0 deletions text/0000-api-doc-frontpage-styleguide.md
Original file line number Diff line number Diff line change
@@ -0,0 1,372 @@
- Feature Name: api_doc_frontpage_styleguide
- Start Date: 2016-07-25
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary

This RFC is a companion to [RFC 1574] concerning API documentation conventions.
This time we focus on the format and style of the "front page" of documentation
as generated by rustdoc. The goal of this RFC is to outline a clear presentation
style for crate documentation that is helpful to new users of a crate. We also
clarify the relationship between the rustdoc front page and the project's
readme. These are the guidelines we will be using for the rust-lang crates, but
are also meant to help guide community crate authors.

[RFC 1574]: https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md

# Motivation

A user's first experience with a crate is often the front page of the crate's
documentation. Taken together with the API documentation and readme, the front
page is a critical piece of understanding a crate's purpose, how to use it, and
its limitations. This RFC furthers our roadmap goal of [providing easy access to
high quality crates][roadmap]. A crate may be otherwise high quality but shoddy
front page documentation can lead people to pass over it.

[roadmap]: https://github.com/rust-lang/rust-roadmap/issues/9

# Detailed design

The front page of the crate should cover three main points. In this RFC, we
cover each in turn.

* [Introduction](#introduction)
* [First Example](#first-example)
* [Capabilities](#capabilities)

## Introduction

The purpose of the introduction is to help a user quickly figure out whether
this is the right crate for them.

In designing the introduction, consider a user searching for a crate to fulfill
some use case, landing on the front page of several similar crates, and trying
to determine which one to pursue further. The introduction is responsible for
concisely conveying what the crate does and why somebody might want to use it.
By the end of the introduction the reader should either be confident that this
is not what they were looking for, or eager to read the example code and
capabilities that follow the introduction.

Here is an example of a decent introduction from the [`log`] crate:

[`log`]: https://doc.rust-lang.org/log/log/index.html

> A lightweight logging facade.
>
> A logging facade provides a single logging API that abstracts over the actual
> logging implementation. Libraries can use the logging API provided by this
> crate, and the consumer of those libraries can choose the logging framework
> that is most suitable for its use case.
>
> If no logging implementation is selected, the facade falls back to a "noop"
> implementation that ignores all log messages. The overhead in this case is
> very small - just an integer load, comparison and jump.
>
> A log request consists of a target, a level, and a body. A target is a string
> which defaults to the module path of the location of the log request, though
> that default may be overridden. Logger implementations typically use the
> target to filter requests based on some user configuration.

Based on the introduction, this crate is not for somebody hoping to compute a
logarithm or a Laplacian of Gaussian. If you are writing a library that wants to
log messages in a way that is governed by the user, or if you are an application
needing to tap into the log output of your dependencies, you should keep
reading.

Another example from the [`rand`] crate:

[`rand`]: https://doc.rust-lang.org/rand/rand/index.html

> Utilities for random number generation
>
> The key functions are `random()` and `Rng::gen()`. These are polymorphic and
> so can be used to generate any type that implements `Rand`. Type inference
> means that often a simple call to `rand::random()` or `rng.gen()` will
> suffice, but sometimes an annotation is required, e.g.
> `rand::random::<f64>()`.
>
> See the `distributions` submodule for sampling random numbers from
> distributions like normal and exponential.

In this introduction it would be valuable to touch on a fundamental question
that many people evaluating a random number library will need to know: where
does the randomness come from? Is it from the operating system? Is there a
pseudorandom number generator? Is it cryptographically secure?

## First Example

The purpose of the first example is to help the reader imagine themselves as a
user of your crate. It gives them a sense of how high level or low level the
crate's primary abstractions are and how some of the verbally described features
play out in practice.

Ideally this example should only demonstrate your crate and core Rust
functionality. Avoid large examples with lots of features; those belong in the
`examples` directory.

Let's look at a good first example from the [`log`] crate. Notice that the
author has focused on getting started, showing how to import and use the crate,
and a few simple uses of common functionality.

```rust
#[macro_use]
extern crate log;

pub fn shave_the_yak(yak: &Yak) {
info!(target: "yak_events", "Commencing yak shaving for {:?}", yak);

loop {
match find_a_razor() {
Ok(razor) => {
info!("Razor located: {}", razor);
yak.shave(razor);
break;
}
Err(err) => {
warn!("Unable to locate a razor: {}, retrying", err);
}
}
}
}
```

## Capabilities

The core capabilities of a crate are the main reason people will use your crate.
In the next section, you can document what each of these core capabilities are
and how to use them. For example, in a crate about random numbers, you may have
sections about: generating random numbers, fitting numbers to statistical
distributions, use in cryptography, thread-local random numbers, and so on.

It is helpful to introduce and give a clear description for each capability
separately to help your readers understand each concept individually before they
begin to combine capabilities.

Here is a good example from the `rand` crate:

> ### Thread-local RNG
>
> There is built-in support for a RNG associated with each thread stored in
> thread-local storage. This RNG can be accessed via `thread_rng`, or used
> implicitly via `random`. This RNG is normally randomly seeded from an
> operating-system source of randomness, e.g. `/dev/urandom` on Unix systems,
> and will automatically reseed itself from this source after generating 32 KiB
> of random data.
>
> ### Cryptographic security
>
> An application that requires an entropy source for cryptographic purposes must
> use `OsRng`, which reads randomness from the source that the operating system
> provides (e.g. `/dev/urandom` on Unixes or `CryptGenRandom()` on Windows). The
> other random number generators provided by this module are not suitable for
> such purposes.

Sample code for each capability should be as simple as possible. In the `rand`
crate, thread safe RNG is demonstrated in 5 lines of code:

```rust
use rand::Rng;

let mut rng = rand::thread_rng();
if rng.gen() { // random bool
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>());
}
```

After this example, a user should immediately be able to use a thread safe
random number generator in their own program.

Examples may go inline under each capability, or all together in an Examples
section.

More complex source examples should be included as a separate program in the
`examples` directory. Be wary of putting large examples in your doc where users
will have to read past the code to get the beginning of your API documentation.

You should avoid examples that require understanding of external crates unless
it is necessary. As a hypothetical example, your logging crate should not
require the user to have experience with [Diesel]. It is okay to leave these
integrations for the reader to put together themselves.

[Diesel]: https://diesel.rs/

# The readme

This is an unresolved question.

# How We Teach This

This RFC will be linked from the [Rust API guidelines] in a guideline dedicated
to front page documentation.

[Rust API guidelines]: https://github.com/brson/rust-api-guidelines

As part of the [Libz Blitz], the community and the libs team will evaluate
high-profile crates against this guideline and file issues where improvement is
required. With front page documentation improving across the ecosystem, users
will learn to depend on it and will notice and complain about crates that fall
short. Those crates can improve their front page experience by using this RFC as
guidance.

[Libz Blitz]: https://blog.rust-lang.org/2017/05/05/libz-blitz.html

# Drawbacks

A possible drawback of this approach is that it risks over-specifying a format
that is ill-served for a particular crate. For example, a crate with a lot of
moving parts may need to use more complex examples because smaller examples lose
educational value or overall impact.

# Alternatives

### Multi-crate guidance

Serde, Tokio, Diesel, and other large projects are factored across many
individual crates. We may provide explicit guidance about how to handle front
page documentation in this situation, beyond just applying this RFC to each
crate individually.

### Example size

We may recommend an upper bound on the size of example code that belongs in the
front page documentation. For example we may say that anything over 40 lines
probably belongs in its own dedicated file in the `examples` directory.

### Example budget

We may recommend only one or two examples of the most basic sort, and links to
`examples` or a website for anything more thorough. During your first
introduction to a crate, links are just as edifying as inline examples. During
your next 1024 times referring to the rustdoc as reference, you are not forced
to scroll past the no longer useful example code.

### Usage section

We may recommend a section or just a lone code block that gives the basic
mechanics of depending on a crate.

```toml
[build-dependencies]
gcc = "0.3"
```

This saves users the effort of:

- Remembering the crate name (crate is gcc, repository is gcc-rs);
- Figuring out what the latest version is;
- Knowing which section to put the dependency into.

### Links to homepage, repo, crates.io

Browsing from a rustdoc front page to any of these other references is currently
obnoxious. On docs.rs they provide these links in a sidebar.

> ![selection_043](https://cloud.githubusercontent.com/assets/1940490/25786542/03e64c0c-334c-11e7-9a1e-868592d663aa.png)

Some crates provide manual cross-links.

> **[Changelog](#) - [API Documentation](#) - [Cargo](#) - [Repository](#)**

We may recommend that crates do something like this in their frontpage. However,
I believe that this should be a feature request for rustdoc instead.

# Unresolved questions

### Readme

What goes in the readme? Do we duplicate all or most of the front page doc in
the readme?

There are some things that have traditionally gone in the readme but not the
front page doc:

- Requisite system libraries
- Code of conduct
- Instructions for developers
- CI status
- Semantic versioning philosophy
- Supported OS and Rust versions
- Comparison with other crates
- Benchmark data
- License boilerplate

Is there a good reason for this distinction?

Here are some projects with very different readmes and front page docs:

- `serde`
[readme](https://github.com/serde-rs/serde/blob/master/README.md)
and
[front page](https://docs.rs/serde/*/serde/)
- `rocket`
[readme](https://github.com/SergioBenitez/Rocket/blob/master/README.md)
and
[front page](https://docs.rs/rocket/*/rocket/)
- `tokio-core`
[readme](https://github.com/tokio-rs/tokio-core/blob/master/README.md)
and
[front page](https://docs.rs/tokio-core/*/tokio_core/)
- `docopt`
[readme](https://github.com/docopt/docopt.rs/blob/master/README.md)
and
[front page](https://docs.rs/docopt/*/docopt/)

Here are some projects with somewhat similar readmes and front page docs:

- `clap`
[readme](https://github.com/kbknapp/clap-rs/blob/master/README.md)
and
[front page](https://docs.rs/clap/*/clap/)

Here are some projects with practically identical readmes and front page docs:

- `serde_json`
[readme](https://github.com/serde-rs/json/blob/master/README.md)
and
[front page](https://docs.rs/serde_json/*/serde_json/)

### Limitations

How best to document a crate's limitations.

### Cargo cfgs

Where documentation for features goes. Serde has this [on the website][serde
website features] and [in Cargo.toml][serde cargo features] but not in rustdoc.

[serde website features]: https://serde.rs/feature-flags.html
[serde cargo features]: https://github.com/serde-rs/serde/blob/v1.0.0/serde/Cargo.toml#L26-L75

### License boilerplate

This crate is licensed under either of Apache License, Version 2.0,
(LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or MIT license
(LICENSE-MIT or http://opensource.org/licenses/MIT) at your option. Unless you
explicitly state otherwise, any contribution intentionally submitted bla bla
bla.

Does this need to be in the readme and/or the rustdoc?

### Getting help

The Serde readme has the following stanza. It is designed to catch new users who
may silently struggle and then abandon the crate without getting help.

> Serde developers live in the #serde channel on [`irc.mozilla.org`]. The #rust
> channel is also a good resource with generally faster response time but less
> specific knowledge about Serde. If IRC is not your thing or you don't get a
> good response, we are happy to respond to [GitHub issues][new serde issue] as
> well.

[`irc.mozilla.org`]: https://wiki.mozilla.org/IRC
[new serde issue]: https://github.com/serde-rs/serde/issues/new

Does this belong in the readme and/or the rustdoc?

### Migration notes

Migration from v1 to v2 is part of in the [`slog`] front page documentation. Is
this an appropriate place?

[`slog`]: https://docs.rs/slog/2.0.4/slog/#migrating-from-slog-v1-to-slog-v2