From f3619d5b435aa6c1d468138e37c117d3390b6227 Mon Sep 17 00:00:00 2001 From: tall-vase Date: Mon, 22 Sep 2025 15:33:52 +0100 Subject: [PATCH 1/4] initial foundations of api design commit --- src/idiomatic/foundations-of-api-design.md | 2 ++ src/idiomatic/foundations-of-api-design/golden-rule.md | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 src/idiomatic/foundations-of-api-design.md create mode 100644 src/idiomatic/foundations-of-api-design/golden-rule.md diff --git a/src/idiomatic/foundations-of-api-design.md b/src/idiomatic/foundations-of-api-design.md new file mode 100644 index 000000000000..6a3c79c4ca66 --- /dev/null +++ b/src/idiomatic/foundations-of-api-design.md @@ -0,0 +1,2 @@ + +# Foundations of API Design \ No newline at end of file diff --git a/src/idiomatic/foundations-of-api-design/golden-rule.md b/src/idiomatic/foundations-of-api-design/golden-rule.md new file mode 100644 index 000000000000..529bb918fa9d --- /dev/null +++ b/src/idiomatic/foundations-of-api-design/golden-rule.md @@ -0,0 +1,4 @@ +# Golden Rule – Clarity & Readability + +```rust,editable,ignore +``` \ No newline at end of file From 91a199e045e334ac683bb6719c3e6b81dee95e1c Mon Sep 17 00:00:00 2001 From: tall-vase Date: Sun, 28 Sep 2025 20:39:36 +0100 Subject: [PATCH 2/4] Initial work on the golden rule: clarity and readability --- src/SUMMARY.md | 4 ++ src/idiomatic/foundations-of-api-design.md | 3 +- .../foundations-of-api-design/golden-rule.md | 46 ++++++++++++++- .../golden-rule/clarity-do-provide-context.md | 58 +++++++++++++++++++ .../readability-consistency-and-shorthands.md | 38 ++++++++++++ 5 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md create mode 100644 src/idiomatic/foundations-of-api-design/golden-rule/readability-consistency-and-shorthands.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index dfd360edf6b4..e32e1da3f18a 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -432,6 +432,10 @@ # Idiomatic Rust - [Welcome](idiomatic/welcome.md) +- [Foundations of API Design](idiomatic/foundations-of-api-design.md) + - [Golden Rule: Clarity & Readability](idiomatic/foundations-of-api-design/golden-rule.md) + - [Clarity: Do Provide Context](idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md) + - [Readability: Consistency and Shorthand](idiomatic/foundations-of-api-design/golden-rule/readability-consistency-and-shorthands.md) - [Leveraging the Type System](idiomatic/leveraging-the-type-system.md) - [Newtype Pattern](idiomatic/leveraging-the-type-system/newtype-pattern.md) - [Semantic Confusion](idiomatic/leveraging-the-type-system/newtype-pattern/semantic-confusion.md) diff --git a/src/idiomatic/foundations-of-api-design.md b/src/idiomatic/foundations-of-api-design.md index 6a3c79c4ca66..6f0b137b3925 100644 --- a/src/idiomatic/foundations-of-api-design.md +++ b/src/idiomatic/foundations-of-api-design.md @@ -1,2 +1 @@ - -# Foundations of API Design \ No newline at end of file +# Foundations of API Design diff --git a/src/idiomatic/foundations-of-api-design/golden-rule.md b/src/idiomatic/foundations-of-api-design/golden-rule.md index 529bb918fa9d..981db64141db 100644 --- a/src/idiomatic/foundations-of-api-design/golden-rule.md +++ b/src/idiomatic/foundations-of-api-design/golden-rule.md @@ -1,4 +1,44 @@ -# Golden Rule – Clarity & Readability +# Golden Rule – Callsite Clarity & Readability -```rust,editable,ignore -``` \ No newline at end of file +```rust,editable +/// The magic function. Important for tax reasons. +fn my_magic(i: u32) -> f32 { + i as f32 + 2. +} + +/// The x function. Foundational for infrastructure reasons. +fn x(i: f32) -> String { + format!("{:.2}", (i / 3.).fract()) +} + +/// Our business logic relies on this calculation for tax reasons, +/// regulatory reasons, or critical infrastructure reasons. So if you +/// see it do be careful about changing how it's handled! +fn taxes_and_infrastructure(input: u32) -> String { + format!("{:.2}", ((input as f32 + 2.) / 3.).fract()) +} + +fn main() { + println!("{}", x(my_magic(128))); + println!("{}", taxes_and_infrastructure(128)); +} +``` + +
+ +- Writing new code is often easier than reading code, so how can we make reading + code easier? By making what is happening at a callsite of functions _as clear + and readable as possible_ before a reader might start referring to the + documentation of the functions and types at play. + +- When reading a codebase, regardless of if you own it or not, you are far more + likely to end up reading _calls_ of functions than the definitions of those + functions themselves. + + This is true across languages, but the communities around Rust (including the + development of the standard library) has settled on a set of things to value + to keep the process of _reading code_ reliable in certain contexts. + +- Ask before running: which function is more readable here, and why? + +
diff --git a/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md b/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md new file mode 100644 index 000000000000..abb68df73401 --- /dev/null +++ b/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md @@ -0,0 +1,58 @@ +--- +minutes: 10 +--- + +# Clarity: Do Provide Context + +Codebases are full of relationships between types, functions, inputs. Represent +them well! + +```rust +pub struct MyType { pub my_number: u32 }; + +impl MyType { + fn add_one(&mut self) { self.my_number += 1; } + fn business_logic() {} +} + +mod another_package { + pub fn add_one(my_type: &mut super::MyType) { my_type.my_number += 1; } +} + +fn add_one(my_type: &mut MyType) { my_type.my_number += 1; } + +fn main() { + let mut value = MyType { my_number: 39 }; + value.add_one(); + add_one(&mut value); + another_package::add_one(&mut value); +} +``` + +
+ +- 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 + where that function comes from. + +- Descriptive names are key, but can be subjective in highly specialized + business logic areas. Try to keep things + +- Demo: Ask for suggestions for what the `MyType::business_logic` method does, + then ask how we might rename the method. + +- Ask: What is the difference in what you assume about the source of the + function `add_one` when it's a method vs when it's a function that takes a + value, or when it's a function from another module? + + - We know what it does, the name is descriptive enough. + + - Potentially different authors, different packages. + + While it makes sense to keep functions as methods a lot of the time, as + there's usually an "authoritative" type, there's still plenty of reasons a + function might not be a method. + + Note: Remember that a method is a relationship between a function and a type. + +
diff --git a/src/idiomatic/foundations-of-api-design/golden-rule/readability-consistency-and-shorthands.md b/src/idiomatic/foundations-of-api-design/golden-rule/readability-consistency-and-shorthands.md new file mode 100644 index 000000000000..6d0ef0560ec8 --- /dev/null +++ b/src/idiomatic/foundations-of-api-design/golden-rule/readability-consistency-and-shorthands.md @@ -0,0 +1,38 @@ +--- +minutes: 5 +--- + +# Readability: Consistency and Shorthands + +Be consistent in function & variable names, and use shorthands with care. + +```rust,editable +// Step 1 +fn do_thing() { /* Imagine something! */} +// Step 2 +fn execute_the_other_thing() {} +// Step 3 +fn anthr_thng_whch_shld_b_dn() {} + +fn main() { + do_thing(); + execute_the_other_thing(); + anthr_thng_whch_shld_b_dn(); +} +``` + +
+ +- Aim to be consistent in how things are named and abbreviated. + +- Shorthands should be used with care, and consistent across a codebase when + used. + +- This example shows three functions that all do "something." Yet each one of + them has a different naming scheme. + +- Ask: Imagine what the domain should be for these three functions. + +- Ask: How should they be renamed? + +
From 8be3ff924a92d71bdbf3fcf2a446f3c9f1991bee Mon Sep 17 00:00:00 2001 From: tall-vase Date: Fri, 3 Oct 2025 16:51:07 +0100 Subject: [PATCH 3/4] Editing pass --- .../foundations-of-api-design/golden-rule.md | 26 ++++++++++++------- .../golden-rule/clarity-do-provide-context.md | 4 +-- .../readability-consistency-and-shorthands.md | 8 +++++- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/idiomatic/foundations-of-api-design/golden-rule.md b/src/idiomatic/foundations-of-api-design/golden-rule.md index 981db64141db..4199b8334d84 100644 --- a/src/idiomatic/foundations-of-api-design/golden-rule.md +++ b/src/idiomatic/foundations-of-api-design/golden-rule.md @@ -1,5 +1,7 @@ # Golden Rule – Callsite Clarity & Readability +A good API or a readable codebase is one that predictably follows conventions. + ```rust,editable /// The magic function. Important for tax reasons. fn my_magic(i: u32) -> f32 { @@ -27,18 +29,24 @@ fn main() {
- Writing new code is often easier than reading code, so how can we make reading - code easier? By making what is happening at a callsite of functions _as clear - and readable as possible_ before a reader might start referring to the - documentation of the functions and types at play. + code easier? + + By making what is happening at a callsite of functions _as clear and readable + 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. -- When reading a codebase, regardless of if you own it or not, you are far more - likely to end up reading _calls_ of functions than the definitions of those - functions themselves. +- _Calls_ to functions are going to be read far more often than the + documentation or definitions of those functions themselves. - This is true across languages, but the communities around Rust (including the - development of the standard library) has settled on a set of things to value - to keep the process of _reading code_ reliable in certain contexts. + This is true across languages, but the communities around Rust settled on + methods to keep the process of _reading code_ reliable in certain contexts. - Ask before running: which function is more readable here, and why? +- Ask: What if we remove the "good documentation" from `taxes_and_infrastructure`? + + Without this documentation, we're only left with what's visible at the callsite. +
diff --git a/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md b/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md index abb68df73401..d5f9593eb481 100644 --- a/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md +++ b/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md @@ -8,7 +8,7 @@ Codebases are full of relationships between types, functions, inputs. Represent them well! ```rust -pub struct MyType { pub my_number: u32 }; +pub struct MyType { pub my_number: u32 } impl MyType { fn add_one(&mut self) { self.my_number += 1; } @@ -51,7 +51,7 @@ fn main() { While it makes sense to keep functions as methods a lot of the time, as there's usually an "authoritative" type, there's still plenty of reasons a - function might not be a method. + function might not be a method or static method. Note: Remember that a method is a relationship between a function and a type. diff --git a/src/idiomatic/foundations-of-api-design/golden-rule/readability-consistency-and-shorthands.md b/src/idiomatic/foundations-of-api-design/golden-rule/readability-consistency-and-shorthands.md index 6d0ef0560ec8..3b00c8119c6a 100644 --- a/src/idiomatic/foundations-of-api-design/golden-rule/readability-consistency-and-shorthands.md +++ b/src/idiomatic/foundations-of-api-design/golden-rule/readability-consistency-and-shorthands.md @@ -8,7 +8,8 @@ Be consistent in function & variable names, and use shorthands with care. ```rust,editable // Step 1 -fn do_thing() { /* Imagine something! */} +fn do_thing() { /* Imagine something! */ +} // Step 2 fn execute_the_other_thing() {} // Step 3 @@ -33,6 +34,11 @@ fn main() { - Ask: Imagine what the domain should be for these three functions. + Expect a broad array of subjects, potential fallbacks: + - Ask: How should they be renamed? + Assume "do_thing" is the convention, so all other functions should start with + `do_` + From 30d126c42307a79f54b9da1dabc93da33b1cfa85 Mon Sep 17 00:00:00 2001 From: tall-vase Date: Fri, 3 Oct 2025 16:56:09 +0100 Subject: [PATCH 4/4] Formatting pass --- .../foundations-of-api-design/golden-rule.md | 6 ++++-- .../golden-rule/clarity-do-provide-context.md | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/idiomatic/foundations-of-api-design/golden-rule.md b/src/idiomatic/foundations-of-api-design/golden-rule.md index 4199b8334d84..c660fa8f3aa8 100644 --- a/src/idiomatic/foundations-of-api-design/golden-rule.md +++ b/src/idiomatic/foundations-of-api-design/golden-rule.md @@ -45,8 +45,10 @@ fn main() { - Ask before running: which function is more readable here, and why? -- Ask: What if we remove the "good documentation" from `taxes_and_infrastructure`? +- Ask: What if we remove the "good documentation" from + `taxes_and_infrastructure`? - Without this documentation, we're only left with what's visible at the callsite. + Without this documentation, we're only left with what's visible at the + callsite. diff --git a/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md b/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md index d5f9593eb481..adc9af35ca81 100644 --- a/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md +++ b/src/idiomatic/foundations-of-api-design/golden-rule/clarity-do-provide-context.md @@ -8,18 +8,26 @@ Codebases are full of relationships between types, functions, inputs. Represent them well! ```rust -pub struct MyType { pub my_number: u32 } +pub struct MyType { + pub my_number: u32, +} impl MyType { - fn add_one(&mut self) { self.my_number += 1; } + fn add_one(&mut self) { + self.my_number += 1; + } fn business_logic() {} } mod another_package { - pub fn add_one(my_type: &mut super::MyType) { my_type.my_number += 1; } + pub fn add_one(my_type: &mut super::MyType) { + my_type.my_number += 1; + } } -fn add_one(my_type: &mut MyType) { my_type.my_number += 1; } +fn add_one(my_type: &mut MyType) { + my_type.my_number += 1; +} fn main() { let mut value = MyType { my_number: 39 };