Skip to content

Conversation

tall-vase
Copy link
Collaborator

Content for the "Golden Rule" chapter of milestone 1.

@@ -0,0 +1,54 @@
# Golden Rule – Callsite Clarity & Readability

A good API or a readable codebase is one that predictably follows conventions.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't how I'd introduce this rule.

I'd more or less directly say that readability at the callsite is more important than the readability of the declaration, or how the API looks on docs.rs.

The single-sentence explanation on the slide would be something like "The golden rule of API design is to optimize for clarity at the point of use (the call-site)."

}
/// The x function. Foundational for infrastructure reasons.
fn x(i: f32) -> String {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function called x is cryptic both at the callsite and at the declaration.

This examples should demonstrate a tradeoff between readability at the callsite and at the declaration.

Better examples would be method names used in From and Into traits.

Normally, method names should be verbs. But in From and Into traits methods are named with prepositions! How come? That's because they optimize for readability at the callsite.

This is exactly where .as_*() and .into_*() naming conventions in Rust come from. These conventions don't optimize for readability at the declaration or in the doc comments, they optimize for the callsite. If they optimized for readability of the declaration, their names would include verbs like .convert_to_foo(), or .borrow_as_str(). That would optimize, for example, for searching for the word "convert" on docs.rs. But the standard library API designers have chosen a different priority. They have established the as, from and into prepositions as short and fluent naming conventions for conversions and borrowing.

(This is actually a good segue to show a brief slide which explains the standard library conventions regarding these prepositions.)

Similarly, Rust uses u32 instead of UnsignedInt32, or even uint32. These names are used so much that they are not read and understood from the first principles every time. The API designers of the standard library intended them to become standalone concepts in the mind of a Rust user.

Importantly, this is not often a tradeoff that an API designer for an "average" API must think about. Most often one can find a name that works well at the callsite and at the declaration. But, especially for foundational and frequently used methods, fluent naming is better.


This point is applicable well beyond naming (however explaining it first using method naming is how I like to do it, this maximizes the 'surprise factor' in the listener and keeps them engaged).

For example,

impl Server {
  // This looks entirely normal at the declaration.
  pub fn new(host: String, port: u16, use_tls: bool, timeout: Option<u64>) -> Self { ... }
}

// ...but the callsite is unreadable. A builder pattern would've been better.
let server = Server::new("localhost".to_string(), 8080, true, None);

Another example:

impl User {
  // Again, this looks entirely normal at the declaration.
  pub fn new(name: String) -> Self { ... }
}

// ...but if most callsites require an explicit conversion, it is a bad API!
let user = User::new("Alice".to_string());

// If we want to optimize for readability at the callsite,
// we could make `new()` take `&str`,
// or make `new` generic, taking anything that converts into `String`,
// like `new<S: Into<String>>(name: S)`.

Please also see the motivating example with HashMap in the documentation for the Borrow trait: https://doc.rust-lang.org/std/borrow/trait.Borrow.html

I honestly would not mind if you show all of these examples on the slides. In fact, since they are quite short, I don't see why we should not include all of them (on separate slides of course).

# Idiomatic Rust

- [Welcome](idiomatic/welcome.md)
- [Foundations of API Design](idiomatic/foundations-of-api-design.md)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please start this section by referencing https://rust-lang.github.io/api-guidelines/ . Explain that students can find many mechanical rules, checklist style, in that resource. "if you are doing X, you should be doing it in this way".

The rules are like, if you're implementing a commonly-used type, you should think whether it should implement Copy, Clone, Eq etc. The rule does not provide you guidance about when to implement Copy and when not to, but it prompts you to think about that.

This deep dive in Comprehensive Rust will no go through that checklist type material. Tell students to explore this resource on their own later.

as possible_ before.

We can't assume a reader has read and memorized all the documentation
beforehand, we need the callsite to provide as much context as possible.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here one common trap API designers fall into is thinking that people who didn't understand what the function does by looking at its name will read its documentation. This is false.

People only open documentation for a function when they are completely lost when reading a piece of code and they believe that this function is the key to understanding. When someone reads a call to a function and they believe they got a general idea of what your function kinda sorta does, they would keep reading the code, they don't open documentation.

<details>

- Context clues let a reader quickly understand details about what's going on.
These can be anything from descriptive names, to if a function is a method, or
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"to if"

where that function comes from.

- Descriptive names are key, but can be subjective in highly specialized
business logic areas. Try to keep things
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incomplete sentence

# Clarity: Do Provide Context

Codebases are full of relationships between types, functions, inputs. Represent
them well!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand the point this slide is trying to make. Is it trying to discuss when something should be a method vs. a free function?

I think more thorough speaker notes and a more clear call to action (than "represent them well") are necessary here.


Expect a broad array of subjects, potential fallbacks:

- Ask: How should they be renamed?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not an actionable question for the audience because these are obviously fake names without semantics. We need to add a specific story for the instructor to use, and work through it in the instructor notes. (We can't rely on the instructor to come up with a compelling API design situation on the spot!)

// Step 2
fn execute_the_other_thing() {}
// Step 3
fn anthr_thng_whch_shld_b_dn() {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would appreciate less contorted examples here. Apart from the obviously bad abbrevs that drop vowels in the third example, the first two look like average fake names for slideware.

@gribozavr gribozavr added the waiting for author Waiting on the issue author to reply label Oct 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deep_dives/idiomatic waiting for author Waiting on the issue author to reply
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants