A Rust Documentation Ecosystem Review
对 Rust 文档生态系统的回顾
@harudagondi
对 Rust 文档生态系统的回顾
阅读时间: 100 分钟
目录
1.1 什么是四个象限?
1.2 为什么它们很重要?这样做值得吗?
1.2.1 Tutorials(教程)
1.2.2 How-to guides(操作指南)
1.2.3 References(参考文档)
1.2.4 Explanation(解释说明)
1.2.5 总结...
1.3 Rust 生态系统回顾
1.3.1 rand
1.3.2 fastrand
1.3.3 chrono
1.3.4 time
1.3.5 jiff
1.3.6 axum
1.3.7 actix-web
1.3.8 rocket
1.3.9 bevy
1.3.10 macroquad
1.3.11 fyrox
1.3.12 thiserror
1.3.13 anyhow
1.3.14 snafu
1.3.15 clap
1.3.16 pico-args
1.3.17 ratatui
1.3.18 egui
1.3.19 iced
1.3.20 wgpu
1.3.21 tokio
1.3.22 smol
1.3.23 embassy
1.3.24 Rust 官方文档
1.4 Crate 分析
1.5 结论
照片来自 Guillaume Piolle.
最近我一直在思考文档的问题。
从轶事的角度来看,记录代码不知何故是程序员最不喜欢做的事情之一。在开发的时候。然而,不可否认的是,文档对于教授初学者至关重要。事实上,人们开始编程之旅最典型的方式之一就是观看 YouTube 视频教程,或阅读书籍,或尝试你选择的“配方”中的示例。如果没有这些资源(或访问这些资源),接触编程和软件开发领域的人就会减少。
显然,文档非常重要。我们阅读手册。我们阅读书籍。我们观看视频教程。然而,对于很多开发者来说,这都是事后才想到的事情,尤其是那些发布库供人们使用的开发者。尤其是对于那些希望自己的库流行的开发者来说。阅读文档是初学者学习的方式,也是专家回忆的方式。
但是什么构成了好的文档呢?
文档质量很难衡量。没有指导方针来确定文档是否符合目标受众的要求。然而,有一些迹象可以表明文档是坏的。一个明显的例子是缺乏文档。如果你没有教授它的方法,人们如何理解你的库?
还有其他更微妙的方式可以说明文档不好。在较新的库中,他们拥有的文档只是 API 参考。你可以收集每个函数、每个类、每个结构体和每个记录的含义,但是将它们组合在一起的方式并不明显。你如何使用 so-and-so 函数?这个库的入口点是什么?为什么这个框架是这样架构的?
有时候,当我在文档中找不到答案时,我不得不求助于在 Discord 上询问别人。我会得到一个答案,我会说谢谢,然后我至少三年都不会想到 Discord 服务器。但是,我会想到下一个会问同样问题的人,以及他们是否会三思而后行是否要使用 Discord。我们不得不承认,Discord 不是一个容易访问的地方。它是一个围墙花园,并且搜索功能已经失效。论坛是更好的解决方案,因为它具有更好的搜索索引和更突出的位置,但在某些地方很少见到。
啊,可发现性。如果不阅读整个 API 参考或花费数百小时的教程,就很难发现新事物。我是否需要阅读每个新添加功能的时事通讯?我是否需要看到一些随机 Discord 频道中一些晦涩难懂的代码?有很多案例中,人们在涉足 Rust 几个月后才发现并重新发现 @
语法,我有点惊讶,因为实际上在模式章节的 Rust Book 中讨论过。难道 Rust Book 不够平易近人吗?
我确信还有许多其他标准可以确定文档的质量,但我想根据我之前陈述的轶事来关注以下三点:
- 全面性——关于该主题的实质内容量
- 可发现性——可以轻松探索新主题
- 哲学——了解库中选择的原因
- 可及性——文档是否令人生畏
当我在思考这些主题时,我偶然发现了这张图片:
这看起来很有趣,因为它将文档整齐地分类为四个主题。让我们调查一下这张图片的含义吧?
什么是四个象限?#
我找到了这张图片的来源。它来自名为 diataxis.fr 的网站。根据该网站,术语 Diátaxis 是指“技术文档编写的系统方法”。它源自古希腊语 δῐᾰ́τᾰξῐς,“dia”表示跨越,“taxis”表示安排。
它提到通过规定一个由四个象限组成的系统来解决知识管理问题:tutorials(教程)、how-to guides(操作指南)、technical reference(技术参考)和 explanations(解释说明)。我建议阅读整个网站以充分理解每个象限的含义,但总结如下:
- tutorial 是一种实践学习体验,用户通过实践学习。
- how-to guide 是一份手册,解决了现实世界的目标或问题。
- reference 是一个事实文档集合,其中包含技术描述。
- explanation 描述了哲学并提供了关于为什么某事物是如此这般的背景信息。
此外,Diátaxis 指南针(指上图)显示了每个系统之间的关系。Tutorials(教程)和 how-to guides(操作指南)由行动驱动;在这种情况下,用户做什么占据了主导地位。另一方面,references(参考文档)和 explanations(解释说明)由认知驱动;用户知道什么是这个故事的主角。
行动与认知并不是我们可以从这张图中提取的唯一轴。当用户想要获取使用库所需的知识和技能时,Tutorials(教程)和 explanations(解释说明)非常有用,而当用户想要将所述知识和技能应用于手头的任务时,how-to guides(操作指南)和 references(参考文档)则很有用。
该网站更全面地概述了每种变体的好文档应该是什么,但现在我不会深入研究。相反,我将在调查 Rust 生态系统对文档的处理方法时,根据需要稍后讨论它。
为什么它们很重要?这样做值得吗?#
我想回到我认为文档中重要内容的标准:全面性、可发现性和哲学。这四个象限如何衡量这些标准(我刚刚编造的哈哈)?
Tutorials(教程)#
在 Diátaxis 系统的上下文中,tutorials(教程)根本不全面。它基于“只学习你需要的”的基础运作,因此它并不旨在讨论可以讨论的关于库的全部内容。因此,其主要目的是只传授必要的知识,而不深入研究事情的细节。这并不是说 tutorials(教程)毫无用处;只是它从一开始就从未打算成为全面的。
它弥补了可发现性。Tutorials(教程)通常是为完全的初学者准备的。它介绍了入门和使用该库所需的主要 API。它使用户知道该寻找什么以及在哪里寻找。当然,它解决了“你不知道你不知道什么”的问题。通过了解与库交互所需的主要和重要接口,它可以快速启动你的旅程,并提供深入研究的机会。
但是,tutorials(教程)不适合解释库的哲学。Tutorial(教程)是一种学习体验,我会说学习与理解不同。你不需要理解为什么函数看起来是某种方式,或者为什么代码库是这样架构的。用户可能只是想做某事,而学习如何做的方法只是一个从 A 点到 B 点的线性、朴实无华的指南。它不是对出现意外结果时该怎么做的真实描述。它不诊断。它是人为的。它不提供选择。它很容易做到,因此对于学习方法很有用,但对于理解哲学则不然。
最后,tutorials(教程)本质上非常平易近人。它假设你什么都不知道。它会引导你。它为你处理所有可能的情况。你只需要按照步骤操作并获得产品即可。简单、容易、快速。
How-to guides(操作指南)#
与 tutorials(教程)针对的是没有知识开始使用库的人不同,how-to guides(操作指南)通常针对的是至少对当前主题具有基本能力的人。它们不是用来学习工具,而是用来使用这些工具实现目标的。它不是用于学习,而是用于在现实场景中应用。因此,how-to guides(操作指南)通常更全面,因为它讨论的内容超出了 tutorial(教程)将要讨论的内容。正如 Diátaxis 网站所讨论的那样,它服务于你的工作,而不是你的学习 † † 区分两者的一个很好的指南是 tutorials(教程)讨论基础知识,而 how-to guides(操作指南)讨论高级知识。现实情况比理想化的场景更复杂。因此,文档应适合这种情况,并讨论可能发生的意外事件和意外事件,以及针对这些事件的适当工具。
作为自然延伸,鉴于预测用户和意外结果的性质,how-to guides(操作指南)比 tutorials(教程)具有更高的可发现性。它必须根据情况提供更多信息。这就需要引入 tutorial(教程)中可能不会介绍的新 API,以防止复杂性使使用者不知所措。
由于 how-to guides(操作指南)以目标为导向的形式,因此解释为什么接口是这样的方式并不是最重要的。因此,像 tutorials(教程)一样,它省略了用于理解的细节,而直接给你答案。
但是,与 tutorials(教程)不同,how-to guides(操作指南)需要基本的胜任力。它不会牵着你的手。它不会理想化场景。它假定你熟悉该主题。它为你提供了必须做出的选择。因此,对于初学者来说,与 tutorial(教程)相比,它的可及性较低,但对于了解自己东西的人来说,how-to guides(操作指南)可能更符合他们的速度。
References(参考文档)#
啊。最常见的文档格式,也是最难接近的文档格式。从其各个部分来说,它是学习库的好方法,但从整体上来说,它不是学习库的好方法。你真的不知道如何开始,也不知道如何解决问题,因为参考文档通常不会给你完整的画面。它对于检查其项目很有用,对于提取项目之间的关系不太有用,并且在完全开发程序时最无用。
就其价值而言,它的设计具有最大的全面性。它(希望)详细描述每个项目,并回答用户的任何和所有潜在问题。它会抛出错误吗?如果是,在哪些情况下以及它返回哪些相应的错误?我有什么特殊的行为需要注意吗?
但是,它并没有很好地解释其哲学。参考文档的设计本质上是冷酷且精确的。没有歧义,完全具有权威性。正如 Diátaxis 网站所说:“人们几乎不阅读参考资料;人们查阅它。”它不是为什么。它是库的什么。
我猜它的可发现性既达到最大值又达到最小值。最大值,因为你可以在这里发现绝对的一切。最小值,因为它不是自然发现任何事物的好方法。这里没有呈现任何动机,因此没有理由现在发现任何事物。
Explanation(解释说明)#
根据我的经验,explanation(解释说明)可能是最稀有的文档格式之一。很少有人会写关于他们以某种方式编写代码的原因。你只会看到更改日志就像 "将 DistString
重命名为 SampleString
",其动机在 PR 中说明。你很少会看到官方文章,说明维护者决定以某种方式架构它,以及为什么有必要这样做。
通过我自己的标准继续分析每种文档格式,explanations(解释说明)对于具有基本能力的人来说很容易理解,并且可以很好地教授其哲学。教授推理是 explanations(解释说明)如此有用的原因。它为用户提供了一种具体的方式来理解事物,而不是像库一样充当黑匣子。它减少了初学者的沮丧感,因为它超越了常见的“它就是它”的响应。它给出了库的动机,为什么它存在,为什么它这样工作,以及为什么不以其他方式工作。它是理解事物最伟大的工具。
它可以成为可发现性和全面性的工具。库的作者/维护者有机会展示你可以使用他们的库制作的理想程序,以及他们展示的哪些函数和类型你可能不熟悉。维护者可以揭示机器的秘密,并可能向你介绍一些在日常使用中通常不会谈论的主题。
总结...#
这是一个简单的表格,根据我设计的标准,我认为每个文档象限可以提供什么:
| Tutorials(教程) | How-to Guide(操作指南) | Reference(参考文档) | Explanation(解释说明) | | --- | --- | --- | --- | | 全面性 | ⚠ | ⚠ | ✅ | ⚠ | | 可发现性 | ✅ | ✅ | ⚠ | ⚠ | | 哲学 | ❌ | ❌ | ❌ | ✅ | | 可及性 | ✅ | ⚠ | ❌ | ⚠ |
图例:
- ✅:达到标准
- ⚠:存在一些不足
- ❌:无法以任何好的方式实现。
乍一看,tutorials(教程)和 how-to guides(操作指南)非常相似,不同之处在于它们的可及性。但是,我在全面性方面遇到的问题是不同的。Tutorials(教程)在不向你介绍所有想法的意义上是不全面的,但它在预测初学者可能面临的每个问题方面是全面的,因为帮助你将是作者的责任。另一方面,how-to guides(操作指南)比 tutorials(教程)更全面,因为它的复杂性更高,但它属于同一种情况,即它不一定向你介绍整个库。
References(参考文档)在设计上是最大程度全面的,但它是唯一在任何方面都不可访问的象限。因此,它对于咨询主题非常有用,但不适用于学习所述主题。
Rust 生态系统回顾#
现在,凭借我们所了解的四个象限和我手头的标准,我们可以调查 Rust 生态系统,看看它们是否符合我们的标准。我将从 blessed.rs 网站中选择一些 crate,以及一些我认为可能对比较有用的未提及的 crate。首先,这是我选择的 crate:
rand
fastrand
chrono
time
jiff
axum
actix-web
rocket
bevy
macroquad
fyrox
thiserror
anyhow
snafu
clap
pico-args
ratatui
egui
iced
wgpu
tokio
smol
embassy
- Rust 的官方文档
我将根据我设定的标准来衡量其文档的质量,并检查我之前讨论过的文档象限的存在。但是,我不会衡量代码或库 API 的质量。这里的目标是检查生态系统是否符合我对良好文档的期望。
rand
#
rand
† † 在撰写本文时,版本为 0.9.1 是 blessed.rs 网站列表中的第一个。所以很自然,让我们先看看它。
crates.io 页面有一个概述,其中链接了不同的随机数生成器 (RNG)、其特性、反特性和平台支持。对于概述来说似乎合理。此外,它有很多指向第三方 crate 的链接,指向它的书(我们稍后将讨论),以及一些开源特定的东西。
rand
的 docs.rs 页面很简单。一个快速入门,然后是指向 The Rust Rand Book 的链接。在我们查看这本书之前,让我们先看看 API 参考。
简短的描述信息量很大,你可以区分每种类型。Rng
/ RngCore
的区别从其名称来看似乎不明显,因此文档通过指出 Rng
是用户级接口,而 RngCore
是实现级接口来解释这一点。此外,函数的文档确实超出了其名称的范围。random
提到了线程本地随机数生成器。random_ratio
† † 请注意,我将名称视为文档的一部分。令人惊讶;该名称暗示返回一个有理数(?),但实际上它返回一个布尔值,并且 true
的权重可自定义。我会将其命名为 weighted_random_bool
,但这似乎太笨拙了。哎呀,命名很难。
trait 和模块确实有更多的实质内容。Rng
有关于其用作泛型的 trait 约束的文档,而 rand::distr
则具有关于概率分布、crate 使用的默认分布以及其他可用分布的高级视图。
我注意到的是,在 docs.rs
页面上没有太多教程和操作指南,除了主页上的快速入门示例。说到主页,让我们看看其中链接的书。
本书的简介包含一个简单的目录,以及与该项目相关的外部链接。略读这本书,它显示:
- 一个更加充实的快速入门示例
- 项目架构、其特性、平台支持和可重复性保证
- 使用
rand
的随机数生成器的综合指南(是的,模拟随机性是一个深刻的主题) - 迁移指南
- 贡献指南
我赞扬主指南和迁移指南;这些是深入、写得很好的文档,为我们提供了这些主题所需的解释。我喜欢我可以发现生态系统中不同类型的 RNG、可用的不同分布、我不知道的主题(随机过程)、RNG 的易出错性和测试随机性。它向初学者讨论术语,给出不同生成器之间的比较,并给出关于其性能和质量的注释。因此,对于对随机生成器具有基本胜任能力但尚未深入研究的人来说,感觉很容易接近。对于绝对的初学者,我认为 docs.rs
和 rand 书中的快速入门示例足以开始。
最后。根据 docs.rs
,rand
已 100% 文档化。好极了。
fastrand
#
根据文档,fastrand
是一个“简单而快速的随机数生成器”。它使用 Wyrand 作为其生成器。
乍一看,它显示了多个简单的示例、其 cargo 特性和关于 WebAssembly 使用的注释。
我对 fastrand
期望不高。它的目标是简单易用。我希望它能提到它使用的分布。它是 100% 文档化,但文档是重复的。但是你能说什么呢?不多。
chrono
#
crates.io 页面讨论了其特性的高级概述,包括指向 proleptic Gregorian calendar 的 Wikipedia 链接。这很好。
docs.rs 上的主页是多肉的。
当然。
时间是...嗯,复杂。
crates.io 页面中的高级概述在此处重复。它还添加了所有 cargo 特性及其用途。它有深入的解释和示例,分组在不同的部分中,并填充了指向相应使用函数的超链接。
即使他们讨论了 chrono
和 time
0.1 之间的关系!
因此,在四个象限方面,explanations(解释说明)和 how-to guides(通过他们给出的配方示例)都成立。它有 tutorials(教程)吗?从页面上收集,我不这么认为。它需要 tutorial(教程)吗?这是一个库。我不认为有一个理想的最终产品可以制作,并具有理想化的场景。时间是一件棘手的事情;一个库需要处理可能发生的任何和所有潜在的事故和问题。因此,主页由多个 how-to guides(操作指南)组成,详细说明了用户可以处理某些情况的不同方式。我如何格式化我的 DateTime
?示例 提供了九种方法,每种方法的输出都不同。
在象限的基础上,我们可以看到有很多 how-to guides(操作指南)和 explanations(解释说明),并且我们判断 tutorials(教程)不是那么必要。参考文档怎么样?
首先,我们可以看到该库已 100% 文档化。好极了。
简短的描述足够清晰。NaiveDate
的描述是“没有时区的 ISO 8601 日历日期。允许从公元前 262145 年 1 月 1 日到公元 262143 年 12 月 31 日的每个 proleptic Gregorian date。还支持从 ISO 8601 序数和周日期进行转换。”,这比仅说“无时区日期”更好。它完成了。它提供了信息。它甚至有一个指向自身的链接,这有点好笑。
单击 NaiveDate
类型会将我引导到其文档,该文档也很广泛。它解释了 proleptic Gregorian calendar 的注意事项。然后,它解释了周日期是什么,以及周日期的年份编号可能与实际的 Gregorian 年不对应。最后,它将序数日期讨论为 chrono
的日期类型的内部格式。
NaiveDate
的子项也很有趣。NaiveDate::MIN
和 NaiveDate::MAX
不仅说明了显而易见的事实(它是最小/最大可能的 NaiveDate
),而且还说明了实际的常量† † 如果你好奇,最小可能的 NaiveDate
是公元前 262144 年 1 月 1 日,而最大可能的 NaiveDate
是公元 262142 年 12 月 31 日。 。一些关联函数还包括“Errors”和“Panics”部分,这表明该项目可能正在使用 pedantic lints!这在我的书中是一个加分项,我只是希望他们挑选并选择而不是盲目地执行 #![warn(clippy::pedantic)]
。
从这个略读中,我会说它有适量的 how-to guides(操作指南)来帮助那些具有基本能力的人,以及一些挖掘事物历史的讨论。但是,需要注意的是,我不太擅长与时间相关的 crate,并且在不阅读 repo 上的问题和听到证明的情况下,不知道文档方面的缺陷。尽管如此,乍一看,这似乎是一个不错的选择。如果你(读者)发现文档中存在一些不足,或者任何文档中的不足,我很乐意了解更多信息,以提高我关于什么使某些文档好或坏的启发法。
就主要部分而言,文档在某种程度上是全面的。当需要时,由于有很多起点可以去,因此可发现性很好。由于大量的 how-to guides(操作指南)及其某些设计的适度解释,它很容易接近。
time
#
crates.io README 仅链接到 docs.rs 页面、Time Book、MSRVP、贡献指南和许可证。与 chrono
相比,我的印象是它有点稀疏,因为它不包括对其使用的日历类型的解释。尽管如此,它链接到 mdbook
页面,这比仅仅将解释和指南放在顶层文档中更有趣。
在我们继续阅读这本书之前,让我们先看看 docs.rs 页面上发生了什么。该页面包含一个关于其特性标志的部分...就是这样。我稍后会评论参考文档。让我们先看看 Time Book。
简介通过其特性来销售 time
crate,包括成为“简单且安全”的 crate,“空间优化且高效”。我不会测试这些说法,因为这篇博客文章的目标是对所选 crate 的文档进行肤浅的分析。相反,让我们继续略读这本书。
我的想法:
- 首先,有些章节没有任何内容。
mdbook
确实支持 草稿章节,所以我很好奇为什么time
没有选择它。 - 有一个名为“How-to guides(操作指南)”的部分和一个名为“Technical reference(技术参考)”的部分。我想知道
time
作者是否知道 Diátaxis 方法。 - how-to guides(操作指南)似乎不是很全面。它仅讨论
Date
/Time
类型的创建和解析。它似乎没有讨论可能的意外情况,例如不存在的日期或闰秒或任何其他情况以及如何处理它们。 - technical reference(技术参考)有一些解释,这有点像我所期望的,当有人制作包含“参考”部分的书时。它讨论了 API 设计中的一些决策以及它们为何制定,或者只是列出语法图(我很欣赏)。