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

Derive documentation can be improved #3189

Closed
2 tasks done
epage opened this issue Dec 16, 2021 · 26 comments
Closed
2 tasks done

Derive documentation can be improved #3189

epage opened this issue Dec 16, 2021 · 26 comments
Labels
A-derive Area: #[derive]` macro API A-docs Area: documentation, including docs.rs, readme, examples, etc... C-bug Category: Updating dependencies S-waiting-on-design Status: Waiting on user-facing design to be resolved before implementing

Comments

@epage
Copy link
Member

epage commented Dec 16, 2021

Please complete the following tasks

  • I have searched the discussions
  • I have searched the existing issues

Rust Version

rustc 1.55.0 (c8dfcfe04 2021-09-06)

Clap Version

v3.0.0-rc.0

Description

the docs on the new derive feature is not great

From mitsuhiko

I think the docs about derive are currently the biggest issue as well. Really liked having all the docs about it in rustdoc, like structopt does.

It's very annoying if you have to jump back into the repo or the GitHub wiki pages to get some extra details. Instead it can be a module just to document the derive feature, doesn't even have to have anything in it, just the docs. And then the docs should be as detailed as in structopt.

So far I always had to go to structopt docs to check how to use the clap derive feature 😅

From dnaka91

I wanted to make sure we captured this feedback and raised visibility of it so we can hear from more voices to help in working out what we shoud do improve this

@epage epage added C-bug Category: Updating dependencies A-docs Area: documentation, including docs.rs, readme, examples, etc... S-waiting-on-design Status: Waiting on user-facing design to be resolved before implementing labels Dec 16, 2021
@epage epage added this to the 3.0 milestone Dec 16, 2021
@epage
Copy link
Member Author

epage commented Dec 16, 2021

My reply on reddit to dnaka91 which hasn't been responded to

So the main point of frustration is going inbetween two different places?

For myself, I have found serde.rs really useful for undertanding their derives while I've always been frustrated with finding anything in structopt's documentation, so I modeled it more off of serde. This ended up both being in structure and not being in docs.rs. I think it really was the structure that was the frustration point for me but there was interest elsewhere in moving stuff out of docs.rs.

So any input on this is helpful for finding how to iterate on this, in whatever form it ends up in the end!

EDIT: I should also add, is your input specifically on the derive or also on the tutorial? The latter especially benefits from not being in docs.rs because we can show the output of the commands and verify its correct! I thought I was going to use this more for the derive docs than I ended up.

@mcronce
Copy link

mcronce commented Dec 16, 2021

FWIW, for me as a clap consumer, an (easily discoverable, maybe linked from or included in the doc comment on the derive macro) comprehensive list of the attributes supported by the macro would be absolute perfect-world

Love the new derive macro, btw. It's fantastic.

@epage
Copy link
Member Author

epage commented Dec 16, 2021

I considered including the derive reference directly in the doc comments but there is a lot shared between Parser, Args, and Subcommand (and where on them you specify it). I felt we needed some place more cross-cutting.

We do link to the derive reference from the top-level docs but linking directly from the traits themselves would be a big help. We've been versioning the links to external documentation, relying on cargo-release to update them. I've been trying to keep those updates to a minimum to reduce boilerplate churn but, unless we move it into an empty module, it pretty much is required here.

Still debating on whether to keep the derive reference in the repo or to move it do an empty module. The tutorials being separate is helped a lot by our ability to test them and link to the example code easily. So far the derive reference only has 1 tested code sample.

@epage epage added the A-derive Area: #[derive]` macro API label Dec 28, 2021
@epage epage removed this from the 3.0 milestone Dec 30, 2021
epage added a commit to epage/clap that referenced this issue Dec 30, 2021
@pinkforest
Copy link
Contributor

pinkforest commented Jan 8, 2022

I actually completely missed the link to derive reference and it gave me headache for hours and then it was all there along front of README.md but for some reason I missed it - it probably has to have a heading in README.md under "Derive" section and then some text around it to give a reference as the plain link is easily ignored - or at least for me it was.

I only got to the refernce documentation when reading the source and associated doc comments somewhere thick deep.

I've created #3269 in order to document what is expected to be supported with flattened in the future.

I've also done crate-ci/clap-cargo#28 to document downstream clap-cargo limitations with the associated required flatten with no alternative to use/inject methods either with individual arguments or as a collective.

@epage
Copy link
Member Author

epage commented Jan 20, 2022

@camsteffen
Copy link

I actually completely missed the link to derive reference

I had the same experience. I had skipped over the table of contents and quickly saw a "Derive API" link which very much looked like it would link to a reference page. When it took me to the tutorial page, I thought "oh I guess this is their idea of documentation". Perhaps these links should instead look like "Derive API (tutorial)" or "Derive API (reference, tutorial)".

@jaskij
Copy link

jaskij commented Apr 19, 2022

Since I randomly found this issue while googling something else, I'll chip in: my main pain point with a Markdown file on Github vs Docs.rs is the lack of navigation - I need to scroll manually, or scroll back to the top and click on a header, there's no floating ToC.

To give an example: reading through Arg magic attributes, I came across verbatim_doc_comment, and wanted to read up more about Clap's doc comment handling. On Docs.rs I would have had a chance to notice the separate section in the ToC in upper right. On Github, if I don't want to loose the place I'm at, I need to copy the address, open a new tab, paste the address, and then I have ToC. Or keep a tab scrolled to ToC.

@epage
Copy link
Member Author

epage commented Apr 19, 2022

@jaskij thats a really good point about the value of a floating ToC. Unfortunately, custom documentation on docs.rs can't participate in the ToC (e.g. clap, structopt).

So let me re-summarize the benefits of the different documentation platforms

mdbook

  • Floating, automatic ToC
  • Manual versioning
  • Inline, testable examples
  • Three places for all project content (docs.rs, GH, clap.rs)
  • Manual cross-linking with rustdoc
  • example

github markdown source rendering

  • Manual ToC
  • Easy versioning
  • Testable examples
  • Only two places for all project content (docs.rs, GH)
  • Manual cross-linking with rustdoc
  • example which links out to gh

github wiki

  • Floating, manual ToC
  • Manual versioning
  • No compiling or testing of examples
  • Only two places for all project content (docs.rs, GH)
  • Manual cross-linking with rustdoc

docs.rs

  • Manual ToC
  • Easy versioning
  • Compileable examples
  • Single place for all documentation (docs.rs)
  • Easy cross-linking with rustdoc
  • example

@jaskij
Copy link

jaskij commented Apr 19, 2022

Actually, GH wiki supports a sidebar - you need a file called _Sidebar.md if my search is correct. But that is still a separate repo

As for mdbook - couldn't you just have the book as a subdirectory in the main repo, and build and publish from there? No need for a separate repository that way.

@epage
Copy link
Member Author

epage commented Apr 19, 2022

With Github, I'm referring to the markdown rendering of source. I've added Github Wiki to the comparison.

As for "places for project content", I'm not referring to repos but places the user has to browse to as that was one of the complaints of using mdbook.

@CraftSpider
Copy link

A quick comment unrelated to the location of the documentation: It took me a while to notice the part that says 'any arg method can also be used as an attribute', because I was looking for how to set a delimiter, and my instinct was to search for 'delimiter', 'comma', 'list', etc. on the documentation, assuming that like the magic attributes they would be listed out. I'm not sure it's worth copying that information, but on the other hand the current setup makes it feel like you need to just read pages of unrelated options to discover it.

@epage
Copy link
Member Author

epage commented May 25, 2022

Yes, I've not wanted to maintain a duplicate of the builder API in the derive documentation. I'm trying to think how to further improve the situation. Maybe we should put the raw attribute description for each type of attribute first since its short, it won't obscure things too badly for the developer more familiar with clap's derive that is wanting more details on a specific magic attribute.

If that sounds good or if you have any other thoughts, let us know!

@jaskij
Copy link

jaskij commented May 25, 2022

As someone who is somewhat familiar with the API, I find myself checking the examples in the repo and then just going off of my knowledge. This is mostly useful for the basics I forgot - like which trait to use.

With the option to just call methods in the attribute, for stuff I don't know off-hand, I often go the other way around - check the methods on the trait, and either check the derive docs for an equivalent or just use the method.

While they are slightly more readable, I'm not entirely sure separate attributes are worth the maintenance effort.

For attributes which are just trait methods with clearer syntax, maybe keep it link-only?

@epage
Copy link
Member Author

epage commented May 25, 2022

Yes, my plan is to just keep linking to docs.rs for people to look up the builder methods to see what they can use as attributes, not even enumerating the builder methods. The challenge at hand, which has been an ongoing one judging by the number of duplicate questions of #3538, is how to help users understand this. My proposal was a tweak to make the raw attribute section for each type of attribute come before the magic attribute one. Any other ideas to help users understand the relationship of the APIs would be appreciated.

@CraftSpider
Copy link

I think putting raw first might help. Looking at the page, If I jump to 'Command Attributes' and skim my eyes down it, I see 'Magic Attributes', then text, then 'Arg Attributes' is the next thing that catches my eye, skipping over 'Raw Attributes'. I think it's a mix of how the header nesting is deep enough that they aren't much bigger than surrounding text, the large amount of block text and occasional bolded text in the magic attributes, and that the magic attributes section is very long while the raw attributes section is short. All together, I missed it the first time because my eyes treated it as part of the above section, moving it first would help because as the shorter section, it will be clear where it starts and ends.

(I'll admit part of the problem is skimming over reading the documentation properly, but I also feel that should be expected of a reference - it's like a dictionary or index, users expect to jump to the part relevant to them)

epage added a commit to epage/clap that referenced this issue May 30, 2022
@epage
Copy link
Member Author

epage commented May 31, 2022

@CraftSpider docs are updated. Hopefully this works out better for the next person!

@Be-ing
Copy link

Be-ing commented Jul 15, 2022

As a new user, I am also finding the documentation scattered and confusing. I've spent like 3-4 hours now trying to understand the basics of clap and evaluating whether it's a good choice for what I'm building. I'm including in this time that I spent looking into alternatives on https://libs.rs because the clap documentation was so confusing and hard to follow. I feel like it shouldn't take nearly this much effort and time for new users to get started and decide if clap is a good fit for their project.

I'll walk through some of my thought process trying to figure out how to start to hopefully illustrate the issues. So, being a Rust library, the first place I expect documentation to be is https://docs.rs/clap. Right away, it's confusing: "This allows using the Derive API which provides access to the Builder API as attributes on a struct" You're using one API to access another API? What does that mean?? I'm already confused. Which API should I use and why? Alright, I'll click the links to the documentation for each API. Start reading each page... I'm still confused, which API should I use and why? I'll try going back to docs.rs, hopefully it's clearer than these overwhelming tutorials on GitHub. Scroll down... aspirations section looks good. Ah, finally an explanation of the differences between the APIs.

Okay, it seems the derive API is probably a good fit for my purposes, but I'm not sure yet, so I want to learn a bit more about each API first. Okay, I'll go back to the tutorials on GitHub. Wait, what even are these APIs? I don't see any code, just command output. Keep scrolling hoping to find code to get a better understanding... nope, still no code. Oh, there are "Example" links... but I thought I was already reading the examples? Alright, I'll click the link anyway. Cool, finally found some code. Wait, what is going on in this code?

#[clap(author, version, about, long_about = None)]

Where do the author, verison, and about information come from?? What is a value_parser and action? What are the differences between these, which one do I want? I guess I'll try to find them in a reference. Go back to docs.rs, can't easily find them. Go back to the derive API tutorial, find the link to the derive API reference. Immediately I'm overwhelmed and give up on that reference. Ah, I guess I'll move on without understanding everything. Okay, the second example has this straightforward code:

#[clap(name = "MyApp")]
#[clap(author = "Kevin K. <kbknapp@gmail.com>")]
#[clap(version = "1.0")]
#[clap(about = "Does awesome things", long_about = None)]

I'm still confused about the very first example without those inline values. Dang, I have a lot of browser tabs open at this point, what was I reading again? Keep reading the tutorial, finally, I find this sentence: "You can use #[clap(author, version, about)] attribute defaults to fill these fields in from your Cargo.toml file." Great! But why wasn't that explained in an inline comment in the source code of the very first example? Keep reading... "Any Command builder function can be used as an attribute." I thought I was reading the Derive documentation, why is this talking about builder functions now? Also, where are those builder functions documented? Should I be using the builder API after all? "Command" looks like the name of a struct, I'll try looking it up on docs.rs... okay, but I'm still lost what the relationship is between what's documented in docs.rs and what I'm reading in this tutorial.

Here are some suggestions to improve this:

  1. docs.rs should immediately give a very high level overview with very simple self-explanatory examples of each API so users can decide which one to read more about
  2. clearer explanations of the relationship between the two APIs with examples
  3. Many more inline comments in the example code. Lots of details feel magical and aren't explained in the tutorials.
  4. Cross referencing from example code to reference documentation
  5. Maybe most importantly, the code should be inline in the tutorials. It's way too hard to follow the tutorials when having to flip back and forth between browser tabs. I think switching to mdbook would be really helpful.

@tshepang
Copy link
Contributor

tshepang commented Jul 15, 2022

I wonder if a (gentle) guide should not be written and pointed to at the top of lib.rs as a "start here". It probably should start with the Builder API, then move to the Derive API.

As a sidenote, I been wanting to write such a guide for a while, sort of a Rust version of this Python one. Other things always got in the way of course, but my main excuse was waitin for clap v3.

@Be-ing
Copy link

Be-ing commented Jul 15, 2022

From fumbling around the documentation and piecing together scattered information, this is my understanding of the APIs. Please correct me if I'm wrong:

  1. The derive API is generally recommended for new code.
  2. The derive API is syntax sugar for the builder API. With the builder API you need to use quite a bit of function-like macros and learn their special syntax; with the derive API you instead use attribute macros on a struct.
  3. With the derive API, you declare what data you want to get out of the CLI in a struct. Clap automagically sets the members of that struct to values parsed from the CLI input.
  4. With the builder API, you create a Command and call various methods to specify the details of how it should parse input, then query the resulting ArgMatches.

@epage
Copy link
Member Author

epage commented Jul 16, 2022

Thank you @Be-ing for working through that and taking the time to reflect on your experience and share it! This will be a big help in finding ways to improve the docs. I especially agree that not providing a more direct guidance on when to use which API is not ideal.

Some of the structure issues and non-inline code blocks is coming from a bad experience where the examples compiled but did not work. Our current form of documentation is tested to make sure that the specified arguments will produce the expected output. I talk more about the different documentation approaches earlier however, I think I thought of a way around some of the problems we had and will take a crack within the next week or so to try to address it.

In supporting users in clap, one of the hardest things has been trying to get across how to use the builder documentation to use the derive API. I still feel like trying to reproduce all of the builder documentation as derive documentation would be a big task that would be hard to keep in sync, so it falls on finding ways to communicate that the derive API is a wrapper around the builder API and how to look things up in the builder documentation to use it in the derive API.

@epage
Copy link
Member Author

epage commented Jul 16, 2022

@tshepang another related resource is https://rust-cli.github.io/book/index.html

@Be-ing
Copy link

Be-ing commented Jul 16, 2022

In supporting users in clap, one of the hardest things has been trying to get across how to use the builder documentation to use the derive API. I still feel like trying to reproduce all of the builder documentation as derive documentation would be a big task that would be hard to keep in sync, so it falls on finding ways to communicate that the derive API is a wrapper around the builder API and how to look things up in the builder documentation to use it in the derive API.

I agree that having nearly duplicate documentation wouldn't be maintainable. Perhaps it could help to have derive macro examples inline in the rustdoc documentation for the builder API?

epage added a commit to epage/clap that referenced this issue Jul 19, 2022
A couple of things happened when preparing to release 3.0
- We needed derive documentation
  - I had liked how serde handled theres
  - I had bad experiences finding things in structopt's documentation
- The examples were broken and we needed tests
- The examples seemed to follow a pattern of having tutorial content and
  cookbook content
- We had been getting bug reports from people looking at master and
  thinking they were looking at what is currently released
- We had gotten feedback to keep down the number of places that
  documentation was located

From this, we went with a mix of docs.rs and github
- We kept the number of content locations at 2 rather than 3 by not
  having an external site like serde
- We rewrote the examples into explicit tutorials and cookbooks to align
  with the 4 styles of documentation
- We could test our examples by running `console` code blocks with
  trycmd
- Documentation was versioned and the README pointed to the last release

This had downsides
- The tutorials didn't have the code inlined
- Users still had a hard time finding and navigating between the
  different forms of documentation
- In practice, we were less likely to cross-link between the different
  types of documentation

Moving to docs.rs would offer a lot of benefits, even if it is only
designed for Rust-reference documentation and isn't good for Rust derive
reference documentation, tutorials, cookbooks, etc.  The big problem was
keeping the examples tested to keep maintenance costs down.  Maybe its
just me but its easy to overlook
- You can pull documentation from a file using `#[doc = "path"]`
- Repeated doc attributes get concatenated rather than first or last
  writer winning

Remember these when specifically thinking about Rust documentation made
me realize that we could get everything into docs.rs.

When doing this
- Tutorial code got brought in as was one of the aims
- We needed to split the lib documentation and the README to have all of
  the linking work.  This allowed us to specialize them according to
  their rule (user vs contributor)
- We needed to avoid users getting caught up in making a decision
  between Derive and Builder APIs so we put the focus on the derive API
  with links to the FAQ to help users decide when to use one or the
  other.
- Improved cross-referencing between different parts of the
  documentation
- Limited inline comments were added to example code
  - Introductory example code intentionally does not have teaching
    comments in it as its meant to give a flavor or sense of things and
    not meant to teach on its own.

This is a first attempt.  There will be a lot of room for further
improvement.  Current know downsides:
- Content source is more split up for the tutorials

This hopefully addresses clap-rs#3189
epage added a commit to epage/clap that referenced this issue Jul 19, 2022
A couple of things happened when preparing to release 3.0
- We needed derive documentation
  - I had liked how serde handled theres
  - I had bad experiences finding things in structopt's documentation
- The examples were broken and we needed tests
- The examples seemed to follow a pattern of having tutorial content and
  cookbook content
- We had been getting bug reports from people looking at master and
  thinking they were looking at what is currently released
- We had gotten feedback to keep down the number of places that
  documentation was located

From this, we went with a mix of docs.rs and github
- We kept the number of content locations at 2 rather than 3 by not
  having an external site like serde
- We rewrote the examples into explicit tutorials and cookbooks to align
  with the 4 styles of documentation
- We could test our examples by running `console` code blocks with
  trycmd
- Documentation was versioned and the README pointed to the last release

This had downsides
- The tutorials didn't have the code inlined
- Users still had a hard time finding and navigating between the
  different forms of documentation
- In practice, we were less likely to cross-link between the different
  types of documentation

Moving to docs.rs would offer a lot of benefits, even if it is only
designed for Rust-reference documentation and isn't good for Rust derive
reference documentation, tutorials, cookbooks, etc.  The big problem was
keeping the examples tested to keep maintenance costs down.  Maybe its
just me but its easy to overlook
- You can pull documentation from a file using `#[doc = "path"]`
- Repeated doc attributes get concatenated rather than first or last
  writer winning

Remember these when specifically thinking about Rust documentation made
me realize that we could get everything into docs.rs.

When doing this
- Tutorial code got brought in as was one of the aims
- We needed to split the lib documentation and the README to have all of
  the linking work.  This allowed us to specialize them according to
  their rule (user vs contributor)
- We needed to avoid users getting caught up in making a decision
  between Derive and Builder APIs so we put the focus on the derive API
  with links to the FAQ to help users decide when to use one or the
  other.
- Improved cross-referencing between different parts of the
  documentation
- Limited inline comments were added to example code
  - Introductory example code intentionally does not have teaching
    comments in it as its meant to give a flavor or sense of things and
    not meant to teach on its own.

This is a first attempt.  There will be a lot of room for further
improvement.  Current know downsides:
- Content source is more split up for the tutorials

This hopefully addresses clap-rs#3189
@epage
Copy link
Member Author

epage commented Jul 19, 2022

The new version of the documentation is now out: https://docs.rs/clap/latest/clap/

Please use this issue for concerns with this approach resolving the concerns in this issue. If things seem settled on the general approach, I will then close this issue.

Please open new issues for new concerns or specific concerns that can be iterated on with the new approach.

@Be-ing
Copy link

Be-ing commented Jul 19, 2022

That's much better, thanks!

@Be-ing
Copy link

Be-ing commented Jul 20, 2022

I think this issue can be closed now.

@epage epage closed this as completed Jul 21, 2022
@epage
Copy link
Member Author

epage commented Aug 18, 2022

As a follow up, raw attributes continue to be a point of confusion so I've created #4090 to further discuss their documentation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-derive Area: #[derive]` macro API A-docs Area: documentation, including docs.rs, readme, examples, etc... C-bug Category: Updating dependencies S-waiting-on-design Status: Waiting on user-facing design to be resolved before implementing
Projects
None yet
Development

No branches or pull requests

8 participants