Rust in Production - 1Password 与 Andrew Burkhart 封面

1Password 与 Andrew Burkhart

1Password with Andrew Burkhart

本集简介

处理机密信息极为困难。你既要确保其安全性(这是显而易见的),同时还需与众多系统集成,始终提供卓越的用户体验,否则人们总会找到规避系统的方法。与同行交流时,许多人提到1Password是一家成功平衡了这些要素的公司。在本期节目中,我与安德鲁探讨了1Password如何运用Rust构建绝不能失效的关键系统,Rust如何帮助他们为数百万用户管理机密信息,以及他们在技术栈中采用Rust所获得的经验。 关于1Password 1Password是一款密码管理器,帮助用户安全存储和管理密码、信用卡信息及其他敏感数据。它提供友好的用户界面和强大的安全功能,保护用户在多设备间的机密信息。 关于安德鲁·伯克哈特 安德鲁是1Password产品基础架构组的高级Rust开发工程师,隶属于框架团队核心平台小组,负责为其他开发者提供构建功能所需的异步框架(例如从原生客户端向Rust核心发起的请求、数据同步等)。他专精于同步流程,实现数据在云端、客户端与原生应用间的双向同步。 节目相关链接 后端前置模式 - 为特定前端创建专属后端的架构模式 typeshare - 从Rust代码生成多语言类型定义 zeroizing-alloc - 1Password实现的Rust最小化安全堆内存释放清零方案 arboard - 用Rust编写的跨平台剪贴板管理器 passkey-rs - WebAuthn Passkey规范的纯Rust实现 WebAssembly (WASM) - 跨平台便携执行的二进制指令格式 tokio - Rust事实标准的异步运行时 Clippy - 用于捕捉Rust常见错误的lint工具集 cargo-deny - 用于检查依赖项、许可证和安全公告的Cargo插件 Nix - 纯函数式包管理器,支持可复现构建 Nix Flakes - 实验性功能,实现Nix构建的封闭性与可复现性 direnv - 根据当前目录加载/卸载环境变量 ACM: Spotify Guilds - 关于Spotify敏捷模型中行会机制的研究 axum - 基于tokio和tower构建的模块化Web框架 tower - 构建健壮网络客户端/服务的库 tracing - 支持异步诊断的应用级追踪框架 rusqlite - Rust中SQLite的易用封装 mockall - 强大的Rust模拟对象库 pretty_assertions - 带彩色差异输出的增强版断言宏 neon - 用Rust编写Node.js原生模块的库 nom-supreme - nom解析器组合器的扩展工具集 crane - 构建Cargo项目的Nix库 Rust实战:Zed - 用Rust构建的高性能代码编辑器 tokio-console - 基于tokio的异步Rust程序调试器 Mara Bos著《Rust原子操作与锁》 - 关于Rust底层并发的免费在线书籍 《Rust编程语言》(布朗大学版) - 带测验的交互式Rust教程 Rustlings - 帮助熟悉Rust代码读写的小练习 官方链接 1Password 安德鲁的GitHub 安德鲁的LinkedIn

双语字幕

仅展示文本字幕,不包含中文音频;想边听边看,请使用 Bayt 播客 App。

Speaker 0

这是《Rust in Production》,一档关于使用 Rust 来塑造基础设施未来的公司的播客。我是 Matthias Entlove,来自 Corode。今天我们将与来自 1Password 的 Andrew Burkhardt 聊谈如何使用 Rust 保障登录安全。Andrew,非常感谢你今天做客。你可以简单介绍一下你自己以及 1Password 吗?

It's Rust in Production, a podcast about companies who use Rust to shape the future of infrastructure. I'm Matthias Entlove from Corode and today we talk to Andrew Burkhardt from 1Password about securing logins with Rust. Andrew, thanks so much for being a guest today. Can you say a few words about yourself and about 1Password?

Speaker 1

当然可以,感谢邀请我来参加。我叫 Andrew Burkhart,是 1Password 的高级 Rust 开发人员。

Yeah. Definitely. Thank you for having me. I'm so I'm Andrew Burkhart. I'm a senior Rust developer at 1Password.

Speaker 1

我在产品基础架构团队工作,或者更准确地说,在组织内部属于框架团队。我们主要专注于异步 Rust 框架。我在这里已经大约三年了,主要负责数据同步方面的工作,这期间随着公司的发展,这项工作也变得越来越有趣。我们的业务也逐渐扩展到其他产品领域。密码管理器一直以来都是我们的核心业务,也是人们过去将近二十年来所熟知我们的原因。

My work on the product foundations team or in the org, I should say, on the frameworks team. So we spoke specifically focus mostly on async Rust frameworks. I've been here been here about three years now and and working on data synchronization mostly, which has been pretty interesting as we grow. I mean, we spread kind of to other products that have come in. You know, the password manager has kind of historically been our our core business, and that's what people have known us for for, you know, almost twenty years now.

Speaker 1

但最近几年,尤其是近年来,我们成长了很多,收购了几家公司,也在安全领域全面拓展。从密码管理器到开发者工具,再到许多企业级密码管理功能。我们有 Connect 服务器等等,这些就像桥梁,帮助进行身份管理。此外,我们还涉足了一些收购的公司,比如帮助实现密钥通行的 Passage、进行设备本地健康检查的 Collide,以及负责配置和类似事务的 Metrolica。因此,在所有这些不同领域中,数据同步是一个非常有趣的用例,它将我们拥有的各种信息以不同的方式整合在一起。

But, you know, over the last few years, especially, we've grown a lot and acquired a few companies and so forth and really spread ourselves across the the security space, you know, with various things from the password manager to, you know, developer tools and a lot of, like, enterprise password management features. And we have things like connect servers and and so forth that, you know, skim bridges that help with identity management, all these things, and then into the companies that we acquired, like Passage, which helps with pass keys, Collide, which does on device health checking, Metrolica, which handles, you know, provisioning and some things like that. So, yeah, so across all those various areas, you know, sync has been a really, really interesting use case to kind of combine all the the various information we have in different ways.

Speaker 0

你说的同步,是指将来自设备或用户档案的信息整合在一起吗?具体是什么意思呢?

And by sync, you mean actually combining all of the information from, like, devices or user profiles, or what does that mean exactly?

Speaker 1

是的。可以这样理解:同步就是将客户端、Rust 核心、服务器之间的数据保持一致,并能再传回到所有相关的客户端。举个简单的例子,你和我使用同一个 1Password 帐户,我在密码管理器中添加了一个项目,你需要立刻看到它,这就是通过同步实现的。此外,在企业环境中,同步也意味着确保一个地方的数据能与另一个地方通信,从而在不同区域之间共享相关信息。

Yeah. So the the sort of summary, I guess, would probably be, you know, federating or or, you know, getting the data to be the same from clients to the Rust core to the server and all the way back around to any clients that are relevant. So that may be something as simple as, you know, you and I are on the same one password account in the password manager, and I add an item that you now need. And so we sync that data across. But it can also be other things like, you know, if you're in the enterprise space, just just making sure that the data from one place talks to another and so forth so that if there is relevant context from one area that is available area, things like that.

Speaker 0

我完全理解这一点,因为最糟糕的开发体验之一就是你期望存在的数据不存在,或者处于某种中间状态。我认为同步必须非常可靠,这是产品的核心。如果同步不可靠,那么其他所有功能都只是表面上的用户体验,而不是真正意义上的良好用户体验。

And I can totally relate to that because one of the worst developer experiences is if data that you expect to be there isn't there or is in a sort of limbo. And Yeah. I think sync needs to be really reliable, and that's the core of the product. If that is not reliable, then, well, everything else is just nice user in experience, but it's not really like, I would say user interface, but not a great user experience.

Speaker 1

没错。这也促使我们形成了一些非常明确的设计模式,比如这里的同步机制。今天早上我们还在讨论这个话题。在我们这里,同步通常是一个后台任务。

Yeah. Definitely. And that's you know, it's created a lot of, you know, patterns, I guess, you would say that we hold pretty strongly to, like, you know, sync here. Conversations about this this morning, actually. Sync here is always sort of a background task.

Speaker 1

因此,无论你正在做什么,同步本质上都应该是它的副作用,并且应该在后台异步进行。这样一来,你就可以始终假设你手头的数据是最新状态,因为同步一直在后台运行,因此你期望这些数据已经被下载到你的本地设备上。这对功能开发者来说带来了一定的自由度,因为你不需要主动去请求数据并等待结果。当然,有些情况下确实需要这样做,但总体而言,大多数数据已经本地化并缓存好了。因此,我可以直接操作这些缓存的数据,就像我是唯一使用这些数据的人一样,这在很多情况下都非常方便。

So anything that you're doing, sync should essentially be a side effect of it, and it should happen asynchronously in the background. And, you know, that way, you kind of always assume that the data you have is current because sync has been happening in the background, and therefore, you have the expectation that that data has already been, you know, brought locally to your device, which gives the feature developers a little bit of freedom because you don't have to go request things and wait for it and do this. I mean, there are cases where that has to happen, but in general, the vast majority of the data has already been brought locally and cached and so forth. So I can just act on that cache as though, you know, I'm the only one using this data or something, which is is convenient in a lot of cases.

Speaker 0

为了实现同步,你竟然需要用到异步机制,这听起来有点有趣。但仔细想想也确实合理,因为同步是在后台发生的,为了让它看起来像是同步的,其实背后需要完成很多工作,而这个过程并不简单。

It's sort of funny that you need async in order for something to be synced, but it does make sense if you think about it because, well, it happens in the background, and it a lot of things need to happen for it to look synchronous, but it's not easy.

Speaker 1

是的,是的,绝对是这样。当你深入探讨诸如同步(synchronous)与同步化(synchronized)等细节时,以及其他类似的问题,我们肯定过度使用了‘sync’这个词,可能已经用得太多了。

Yeah. Yeah. Definitely. And and you get into the the nitty gritty details of, like, synchronous versus synchronized and and so forth, and and we definitely overload the word sync probably way too much.

Speaker 0

那么让我们回到几年前你刚开始的时候。我想你刚才说你在1Password已经工作三年了。那时候你的背景是什么?你来自哪里?还有,当你开始的时候,1Password中Rust的状况是怎样的?

So take us back a couple years ago when you started. You said you're at 1Password for three years now, I guess. What was your background back then? Where do you come from? And then what was the state of Rust at 1Password when you started?

Speaker 1

好的。我之前的工作主要是使用Kotlin和Spring Boot,这其实有点像Kotlin的后端开发框架。我做了很多这类工作,比如后端Web编程。我也稍微接触过前端,使用TypeScript和Vue框架做UI开发,但我并不是一个专职的前端开发者。我们通常称之为BFF模式,也就是每个前端都有一个专门为其服务的后端,来处理特定的业务逻辑。

Yeah. So I had done mostly my prior job had been a lot of Kotlin and Spring Boot, which, you know, is kind of like it's a framework for Kotlin doing server side stuff. And I was doing a lot of that, like like back end web programming. I also worked on the front end a little bit with TypeScript and the Vue framework for UI, but I wasn't really, like, a front end developer. I did we you know, it's referred to, I think, as, like, the BFF pattern where, like, you have one server that manages a lot of different things, and then you have all these front ends that manage pieces of that.

Speaker 1

对吧?举个例子,我曾经参与过一个处理大量设置的应用,这些设置更多是后台配置。然后我们还有许多其他应用,是实际终端用户会交互使用的。所有这些应用都由一个主服务器提供支持,但为了避免这个主服务器被各种不同的API调用搞得混乱不堪——当然,你也可以选择使用GraphQL之类的工具——我们创建了BFF服务器,每个前端都有自己的后端,再由这些后端对接到底层真正的后端服务。所以我一直从事的是这种中间层的开发工作。

Right? Like, for example, I worked on an app that did a lot of settings, like, behind the scenes settings, and then we had a lot of other apps where actual end users would interact with it. And the one main server powered it all, but instead of muddying that server with, you know, all these either well, you know, like, you could use something like GraphQL, I suppose. But, like, instead of muddying it with all these APIs that supported vastly different use cases, we created these BFF servers where each front end has its own back end that then translates to the real sort of underlying back end. So I'd always done kind of that mid layer of of development.

Speaker 1

这其实非常有帮助,因为后来当我了解1Password中Rust的使用情况时,发现它的架构也是类似的。我们每个应用——当然,我们有很多应用,包括iOS、Android、Mac、Windows、Linux、网页和扩展等平台上的应用——它们都是原生客户端。比如iOS应用是用Swift写的,然后它们都嵌入了一个后端,这个后端是用Rust写的,我们称之为‘核心’(core)。

And that was actually very helpful because it turns out, you know, getting into the state of Rust at one password is that's kinda how Rust is used here. So each of our apps, you know, obviously, we have quite a few between iOS and Android and Mac and Windows and Linux and web and extension and all these different places. All of them are native clients. So they operate you know, the iOS app is in Swift and so forth, and then they are bundled with kinda like an embedded back end, which is a Rust. We call it the core.

Speaker 1

所以这个Rust核心被嵌入在所有这些客户端中,它承担了尽可能多的业务逻辑,使得这些原生客户端只需专注于显示层或展示层。然后它再与真正的云服务器等进行通信。因此,Rust在这里被采用了。我其实不太清楚具体是什么时候开始使用的,但据我了解,最初是为了开发Windows应用而引入的。后来,从1Password 7到1Password 8的过渡期间,我记得是在我加入之前不久。

So the Rust core is is inside of all of these, and that is doing as much of the business logic as we can to leave those native clients to just be display layer, essentially, or presentation layer. And then that communicates to the actual cloud server and so forth. And so Rust got picked up here. I don't actually know when it was, but my understanding is it was originally picked up for the Windows app that was being built. And over time, when we got from 1Password seven to 1Password eight, I think it was this again, it was it was slightly before me.

Speaker 1

但我想那时候的想法是:我们需要更多的跨平台功能,因为我们正在开发的许多功能已经远远超出了最初的密码管理范畴。我们需要在所有这些平台上实现各种不同的功能,但这些功能又不得不被反复实现多次。

But I think that was when it was like, hey. We need more cross platform functionality because we're building so many features that were not originally just password management concerns. Right? We're building all these different things, and they need to work on all these platforms. And we're implementing them over and over and over again.

Speaker 1

于是他们决定创建一个统一的核心来驱动所有应用。当时他们已经在Windows平台上开始使用Rust,并且效果很好,于是很多代码就被迁移了过来。当我加入的时候,正好是2022年,公司正处于快速扩张阶段,来了很多新员工。Rust随着核心功能的开发迅速普及开来,包括各种开发者功能和其他功能。就在那时,我们进行了开发团队的重组,成立了我现在所在的框架团队,还有其他一些团队,比如专门负责安全开发或平台特定开发的团队,比如处理Windows、Android等平台的细节。

And so when they decided they wanted to create sort of the singular core that was going to power all the apps, they had already started to use Rust on Windows, and it had worked really well. And so a lot of it just got ported over. And so when I got here, we were just in this kind of big growth phase back in 2022 and a ton of new people coming in. And so Rust was sort of proliferating very quickly as the core was building, you know, all these developer features and these different things. And it was right about then we did a reorg of the development teams and created the team that I'm now on, which is the frameworks team, along with a few other teams that do, for example, like security specific development or platform specific development, like handling the nuances of Windows or Android or whatever it might be.

Speaker 1

我们这些团队一起合作,设计出了一些关于Rust开发的模式、规则等,试图将各种不同的开发活动统一起来。这也逐渐形成了我们现在所采用的开发模式,这些模式确实帮助我们尽可能地保持了这个庞大核心的可维护性。

And all of us kinda came together to design patterns and rules and and so forth around Rust development to try to sort of wrangle all these different things that were happening. And that's kinda got us into the patterns that we we have today, which which have been really nice to, you know, keep this giant core as as maintainable as possible.

Speaker 0

很好。我稍后想再回到这些模式的问题上。但在那之前,我想先问一下你们在使用Rust之前用的是什么?是不是非常依赖平台?比如你们的业务逻辑是不是分别用Kotlin、Swift等语言实现?

Nice. I want to get back to the patterns in a second. But before we do that, what did you use before Rust? Was it very platform dependent? Did you have this business logic in, for example, Kotlin and then Swift and so on?

Speaker 1

是的,没错。正如我所说,那都是我来之前的事了,但据我了解,当时所有东西基本上都是用各自平台的原生方式开发的,这确实带来了一些优势,对吧?这样做有好处也有坏处。

Yeah. Exactly. So so, like I said, that was all before me, but I my understanding is that everything was basically built natively, which gives you some benefits. Right? There are there are pros and cons of that.

Speaker 1

但以我们现在的规模,拥有如此大量的代码和如此多不同的实现方式已经不可行了。而且很明显,当你在开发一个安全类应用时,多个不同的实现会成为一个问题,对吧?每次你必须这么做时,这些实现中的某一个可能会以其他实现没有的方式存在漏洞,这就带来了风险。我们要比较 Swift 代码和 Kotlin 代码、TypeScript、Go 等等,确保它们都在做完全相同的事情,但这些语言在异步处理、内存管理等方面可能有不同的底层模型。

But at the scale that we're at now, it's just not feasible to have that much have that much code and have that many different implementations. And, obviously, just when you're building a security app, you don't multiple implementations is a problem. Right? Anytime you have to do that, there is now the risk that one of these implementations is vulnerable in some way that the other isn't. And we're trying to compare, you know, Swift code to Kotlin code to TypeScript to, you know, Go or whatever and so forth and make sure that these are all doing the exact same thing, but those languages may have different underlying models for async or memory management or whatever it is.

Speaker 1

因此,继续这样下去是不可行的。而 Rust 核心部分真的帮了我们大忙了。它实现了我们以前根本无法实现的功能。

And so it it just wasn't feasible to continue on like that. And so the Rust core really helped us to I mean, it just enabled features that we really weren't that that weren't possible before.

Speaker 0

从我理想化的角度来看,我希望发生的情况是,一旦你将所有这些代码合并到一个代码库中,一个统一的 Rust 代码库中,你就能看到不同平台、不同语言或不同的开发者是如何解决这些问题的,其中一些人可能解决了不同的边界情况。当它们被整合在一起时,你就得到了一个比各部分更强大的整体。这种情况发生了吗?

In my idealized way to think about it, what I hope would happen is that once you merge in all of that code into one code base, into one Rust code base, that you see how different platforms or different languages solve these problems or different developers solve the same problem, and some of them solve different edge cases. And then when you merge that together, you get a thing that is stronger than its parts. Did that happen?

Speaker 1

是的,我认为是这样。我觉得同时也会出现相反的情况,对吧?比如我们会看到一个组件,然后说,这东西到底在做什么?

Yeah. I think so. I think and you get the opposite too. Right? Where it's like, you know, we'll we'll get one component, and it's like, what is this thing doing?

Speaker 1

原来是,哦,我们是从另一个版本移植过来的。哦,那是最糟糕的一个版本,我们为什么选了它?所以你确实会遇到这种情况。

It's like, oh, we ported that from this other version. Like, oh, that was the worst version. Why did we pick that one? You know? And so so you do see that.

Speaker 1

不过,是的,我认为在很多方面,你确实得到了这种好处。我们也能从原生客户端中看到这一点。比如我们有开发者在 Swift 和 Mac 开发方面有二十年的经验,他们参与进来后会说,好,我们需要开发这个功能。

But, yeah, I think in a lot of ways, you definitely get the benefit of that. And and we see that having native clients. I mean, we've got developers who have done Swift and Mac development for, you know, twenty years or whatever it might be. And so then they come at it, and it's like, okay. Hey.

Speaker 1

我知道我需要在 Rust 方面得到一些帮助。当你看到某些实现时,你会说,这完全不是我会想到的做法。他们则会说,哦,这在 Mac 平台上我们是这么做的。于是你开始获得一些有趣的新想法,关于你可以如何处理、如何解决各种问题。

We need to build this feature. You know, I need some help with the Rust side of it. And you see something, and you're like, that's not at all how I would have thought to do it. They're like, well, here's how we do it, you know, in Mac land. And you start to get interesting new ideas, I think, about how you can handle you know, how you can tackle various problems.

Speaker 1

所以我认为,仅仅因为有这么多不同的开发者,我们就自然而然地获得了这些东西。我们确实看到了 Rust 核心的发展过程,在尝试整合各种实现的过程中,以及现在尝试将我们之前在浏览器端原生实现的一些浏览器功能整合进 Rust,并编译成 Wasm 的过程中,我们又看到了一些类似的模式,这些模式可以帮助我们不断学习和改进。

So I think we get that just by nature of having all the different developers, but we definitely saw it in the the growth of the Rust core and trying to trying to pull things together and now trying to add in some of the the browser features that we had implemented natively in the browser. Now that we're trying to pull them into Rust and compile them into Wasm, we're seeing some of those patterns again that we can, you know, learn from and improve throughout.

Speaker 0

Rust 生态系统是否已经准备好满足 1Password 对它的需求?例如,在 crate 生态系统中是否存在什么空白或不足?

Was the Rust ecosystem prepared for what 1Password asked it to do, or were there any gaps in the crate ecosystem, for example?

Speaker 1

我觉得可能确实存在一些这样的工具。总体来说,我认为是这样的。我觉得当时的生态系统发展得非常迅速,有很多人在开发有趣的东西,这为我们提供了很大的创新空间。当然也存在一些小的空白,也就是我们发布的一些 crate 所填补的地方。比如说,像原生客户端这样的东西,通过 FFI 并不一定能实现类型安全。

I think there were probably some. I I would say in general, yes. I think the ecosystem was growing so fast, and, you know, there were so many people building interesting things that I think it gave us a lot of a lot of freedom to to innovate on top of those. I think there were small gaps, which is where you've seen some of the crates that we've put out. Gaps like, for example, you know, having those native clients, there's no type safety across the FFI necessarily.

Speaker 1

如果我正在写 Swift,然后我通过 FFI 把某些数据发送到 Rust 核心代码,我只能希望两边的类型能够匹配。因此我们创建了 Type Share crate,它虽然不能提供完整的类型安全性,但至少可以确保你不需要在客户端手动编写类型。这些类型是根据你的 Rust 代码生成的,这样当 Rust 代码发生变化时,客户端的类型也会随之改变,你不需要手动去同步它们。这对我们来说非常有帮助。

If I'm writing Swift and then I send something into the FFI and then into the Rust core, I'm just hoping the types line up. So we created the type share crate, which is it it's not giving you necessarily complete type safety, but it is at least making sure that you're not writing the types on the client side. They are generated from your Rust code so that if the Rust code changes, the client side types change. You're not having to manually keep those in sync. So I think that's been really helpful.

Speaker 1

除此之外还有一些其他的小工具。我们最近发布了一个叫做 Zeroizing Alloc 的 crate,它其实是对全局分配器的一个封装,确保在使用它的时候,每当内存通常会被释放时——也就是被系统回收并用于其他用途时——我们不会让这些内存一直保留其中的数据。

And then there are other little things. Another one we released somewhat recently is called Zeroizing Alloc, which is is like a wrapper around the global allocator that makes sure, you know, if you're using this, whenever memory would normally be deallocated, which in that case, you know, it's sort of just dropped. Right? It's free for the system to use for other things. We don't wanna just let that sit around in case the system doesn't need it, and that memory sits there forever.

Speaker 1

对吧?当你处理敏感数据时,这种情况是不能接受的。因此 Zeroizing Alloc crate 可以在内存释放的过程中将这些内存中的数据全部清零。像这样的小工具显然 Rust 语言本身已经具备了实现的条件,只是之前可能没有这样的使用场景。

Right? We can't have that when you're dealing with sensitive data. So the zeroizing alloc crate will help to just flip those all back to zeros during that that deallocation process. So there were little things like that that that obviously Rust as a language was ready for. There just hadn't been that use case necessarily.

Speaker 1

所以我觉得这些小空白正好为我们提供了一些机会,让我们可以去填补它们。

And so I think it it created nice gaps for us to to fill with some of those things.

Speaker 0

是的。我之前看到过那个 Serializing Alloc crate。其实是在那之前就看到了,因为链接显示为紫色,所以我记得。我很惊讶之前居然没有人开发这样一个 crate。你是看过一些类似的 crate 但不太满意吗?

Yeah. I came across this serializing analog crate. Actually, before that because the link was purple, so this is how I know. I'm surprised that no one else built such a crate before. Or did did you look at some and didn't really like them?

Speaker 1

我不太清楚我们是怎么发现它的。某种程度上我也在想,如果你看一下这个 crate 的实现,并不特别复杂。它其实是一个相当直接的实现。我也在其他情况下见过类似的事情,就是我们遇到一个问题,然后觉得:哦,这太简单了。

I don't know how we came across that. And I wonder to some degree, like, if you look at the crate, it's not particularly complex. Right? It's a fairly straightforward implementation. And I've seen this in other cases where I think sometimes we look at a problem and we go, oh, it's so simple.

Speaker 1

根本不需要专门做一个 crate 来解决这个问题。这个问题可能很常见,但大家觉得:我自己随手写一个就行了。也许人们不太想引入额外的依赖。于是大家就自己动手写一个类似的实现。

Like, I don't need to make a crate to deal with this problem. You know? It's it's maybe a common problem, but it's like, I'll just throw this together. And, you know, maybe people don't want the dependency or something like that. I'll just kinda hand roll it very similarly or something along those lines.

Speaker 1

我觉得这种情况经常发生。对吧?人们有时候确实会对依赖项比较谨慎,尤其是那些只做小事的依赖项。比如在 TypeScript 的 NPM 生态中,就发生过 left pad 事件。你知道的,那个包做的事情就是处理左对齐填充。

I think sometimes that happens. Right? And and people are obviously wary sometimes of dependencies, you know, especially ones that do smaller things. Right? We saw, I think, in the the TypeScript NPM world, there was, like, the left pad incident, right, where, like, all this thing is doing is handling this left padding.

Speaker 1

它非常简单,但一旦它被移除了,整个生态就出现了大问题。所以这可能就是为什么有些工具没有被开发出来的原因。也可能是……我们不一定是第一个想到它的人。

It's so simple, but then when it's gone, now we have a big problem. You know? And so that could be the reason that that some of those things just don't get created. It may not be you know? I I doubt we were the first people to think of it.

Speaker 1

你知道吗?这可能是别人以前已经解决过的问题。他们可能只是没有为此创建一个 crate,或者类似的事情。或者也许外面已经有一个了,只是我还没看到。

You know? It's probably something someone else had solved before. They maybe just didn't make a crate for it or something like that. Or maybe there is one out there, and I just haven't seen.

Speaker 0

在 1Password 创建 crate 的政策是怎样的?

What is the policy around creating crates at one password?

Speaker 1

你知道吗,我在这里看到一个很有趣的现象,就是 1Password 这个密码管理器的概念已经有 20 年的历史了,对吧?而且从概念上来说,很多地方和当时还是一样的。而 Rust 应用本身,现在也有五、六、七年了。我也不太清楚它的确切年龄,但它已经存在很长时间了。

You know, I there's this has been an interesting thing that I've seen here, right, is because one password, the password manager concept, is 20 years old. Right? And and conceptually, a lot of it is similar to what it was then. And then the Rust app itself, you know, now is, you know, five, six, seven years old. I don't know exactly how old, but it's been around a while.

Speaker 1

你看到这些事物已经发展得非常庞大了。大多数情况下,内部创建新的 crate 只是一个代码架构的问题:这样做是否有意义?是否有必要进行这种分离?对吧?

You have these things that have grown so much. And for the most part, creating new crates internally, it's just a matter of, you know, code architecture. Does it make sense? Is it is it a necessary separation? Right?

Speaker 1

你在任何地方都会遇到很多这样的问题。将 crate 开源有时会比较棘手,首先你得想清楚这样做是否值得公开。比如我们的 Zeroizing crate,我们本来也可以把它留在内部,但我们觉得它可能对一些人有帮助,而且它也不是 1Password 所独有的、私密的秘密技术。

A lot of problems you deal with anywhere. Making crates public is sometimes tricky because, one, you have to figure out, does this make sense to make public? Right? Like, Zeroizing Alec, we probably could have left that internal, but we figured it might help some people. And it's not like a, you know, private, you know, secret thing that 1Password does.

Speaker 1

我想很多人也知道,我们必须以这种方式处理内存。所以你一开始会有些顾虑,是否应该将它公开。然后还要深入地把它从过去几年中你构建的其他所有东西中剥离出来。对吧?比如我们的剪贴板管理器。

I think a lot of people know that, you know, we have to deal with memory this way. So you have some of those initial concerns about whether or not we should make this public. And then it's deep like, untangling it from everything else you've built over the last few years. Right? And, you know, there are things like our, you know, clipboard manager.

Speaker 1

它叫做我们的 board,现在已经被公开了。你得想,我们之前有很多 1Password 特有的假设,可能已经嵌入其中。现在我们必须把这些假设抽离出来,让这个 crate 看起来就像一个第三方依赖一样,对我们自己也是如此。

It's called our board that's made public. You know? And you gotta go, okay. Well, we had all these, you know, 1Password specific assumptions that may have been baked in. So now we have to pull those out and make this just a dependency as though it were a third party dependency to us as well.

Speaker 1

你知道吗?所以很多时候,这个过程就是一点点地剥离各种耦合。至于是否决定开源,我想这很大程度上取决于具体的情况。我觉得我们一直在努力把越来越多的项目开源出去。例如,我们发布了 PasskeyRS 这个 crate,我认为它可能只对其他密码管理器有用。

You know? And so a lot of it is just just small bits of process of untangling things. But but as far as deciding to make it public, that's pretty case specific, I guess, or situation specific. And I think we've been trying to to get more and more out there. You know, we released, for example, the PasskeyRS crate, which I think is only valuable to other password managers.

Speaker 1

我不确定是否有人会用到它,因为它主要是用来验证 passkey 的。我不确定是否真的有人会需要它。但无论如何,我们还是发布了,一方面它可能对别人有帮助,另一方面我们也希望看到 passkey 被更多应用采用,即使是在竞争对手的应用中。我们希望它能被广泛使用,等等。而且,它本身也是用 Rust 编写的,其他人可能也能从中学习到一些东西。所以,是的,具体情况具体分析,但无论如何,这都需要一定的工作量。

Like, I don't know if there's anybody because it really just validates like, does verification of passkeys, and so I don't know that anyone else would ever need it. But, you know, we released it because, one, it might help them, and we really wanna see passkeys get adopted in more places even if that's, you know, in a competing app. We wanna make sure that that's available and and so forth. And it's also just interesting, you know, Rust that people might be able to learn from and so forth. So, yeah, it definitely depends on the situation, but it's it's it's a bit of a process either way.

Speaker 0

也许某个听众会查看这个 crate,并构建出我们俩都没想到的东西。这种事情发生的频率比我想象的还要高。另外,无论是否使用 Rust,开源软件对于每家公司来说都是一项巨大的工程,因为很多人忽略的是,除了代码之外,还有版本管理、文档编写、测试、持续集成、沟通等等一系列工作。同时,它也在一定程度上暴露了公司在内部构建软件的方式,而且很多开发者其实很害怕公开他们写代码的方式。你有没有收到过任何外部的贡献,让它变得值得这么做?

Maybe one of the listeners checks out that crate and builds a thing that we both haven't anticipated. It happens more often than I expect. And the other thing is open sourcing software, whether it's Rust or not, is a huge lift for every company because what a lot of people forget is everything other than the code, versioning, documentation, testing, CI, communication, and so on. And also, to some extent, exposing how you build things at a certain company, and also a lot of developers are, like, afraid to share how they write code. Did you ever get any external contributions to make it worth it?

Speaker 1

是的。我的意思是,尤其是像TypeShare这样的项目,我正在努力回想它是用什么语言开发的。我想应该是Scala之类的语言。比如说,我们自己并没有使用Scala,因此我们从未开发过TypeShare与Scala的集成,但社区中有人做了这个。所以现在我想应该就是Scala吧。

Yeah. I mean, especially, like, with TypeShare, I think I'm trying to think of what language it was. I wanna say, like, Scala or something like that. Like, some you know, we don't use Scala, and so we never built, you know, a TypeShare integration with Scala, but someone from the community did. So now that I I wanna say it's Scala.

Speaker 1

现在确实具备了将Rust类型转换为Scala等功能。我认为这些功能挺不错的。我不确定我们是否曾经真正开源过什么东西,并希望人们能在此基础上开发我们需要的功能。一般来说,我们通常的做法其实是反过来的,比如确保我们的工作能在可能的情况下帮助到其他人。就像你所说的那样,这可能会很棘手,特别是从运维角度来看更是如此。

Now there is, you know, the the capability to convert your Rust types into Scala and so forth. And I think those are nice. We don't I don't know that we've ever really open sourced anything with the hope that people would build features that we need. I mean, you we we generally are trying to do it sort of the other way around, like, you know, make sure that our work is helping people where we can. Like you said, it it can be tricky, especially just from an operational standpoint.

Speaker 1

对吧?我记得我看到过一些数据,比如我们有大约15万家公司使用1Password,或者甚至更多。哇。所以当用户数量达到这个级别时,他们的需求自然也非常多,对吧?

Right? There's I think I saw some we have, like, a 150,000 businesses that use 1Password or something like that or more than that. Wow. So when you have that number of people, the number of needs is pretty high. Right?

Speaker 1

我们有很多公司提出各种各样的需求,这家公司需要这个功能,那家公司需要那个功能,等等。如果你开源了某个项目,你就失去了快速进行重大变更的能力。对吧?你当然从技术上来说可以这么做,但这样不是一个好的开源项目,对吧?如果你总是频繁地破坏兼容性。因此,其中一个难点就是,当你做决策时,需要考虑这个项目是否适合开源?

We have a lot of, you know, this company needs this thing and this company needs this thing and so forth. And if you open source something, you lose the ability to make breaking changes quickly. Right? You don't want to I mean, I guess you technically could, but that's not a very good open source project, right, if you're just breaking it all the time. So that's one of the harder parts is, you know, when you're making that decision, is this something we can open source?

Speaker 1

以及我们是否能够像你所说的那样,提供版本控制?比如,我们是否能够做出某种承诺,比如如果我们发布了版本一,它稳定、安全、可靠,那没问题。但如果我们现在因为我们要构建的某些新功能而需要发布版本二,并且这是一个破坏性更新,那么版本一实际上就变得不再被支持了。所以如果你的需求无法兼容版本二怎么办?如果版本一存在安全漏洞怎么办?那么你就创建了两个分支,都需要有人来维护。

And can we give, you know, like you said, versioning? Like, can we give any kind of guarantee that, like, if we make version one and version one is stable and safe and it's good, that's fine. But now if we need to make version two a breaking change because we need it for something we're trying to build, well, now version one kind of becomes unsupported. So if version two doesn't work for what you're trying to do, well, now what if there's a security vulnerability with version one? Now you've created these two branches that should be maintained by someone.

Speaker 1

如果这种情况再次发生第二次、第三次,你就会制造出一个复杂的问题网络。所以,如果我们能将所有东西都开源当然是件好事,让所有人都能看到。我确信有办法实现这一点。只是这并不容易。就像你所说的那样,这非常具有挑战性。

And if that happens a second time and a third time, you just create this web of of challenges. So, you know, it would be great if we could open source everything, you know, and let everyone see all that. And I'm sure there are paths to that. It just doesn't it's not very easy. Like you said, it's very challenging.

Speaker 1

这并不像我们简单地把它公开出来那么简单。你需要做大量的管理工作才能让它真正运作起来。而且,随着事情的发展变化,想要持续地、负责任地、可靠地维护它,其实是非常困难的。

It's not as simple as, like, we'll just make it public. You know, you've gotta do a lot of management to make that work. And, you know, as as things ebb and flow, that can be really hard to to keep up with, you know, responsibly and reliably.

Speaker 0

是的。即使你没有开源,只是在不同团队之间共享一个crate,这本身也是一个挑战。你们使用的是单体仓库吗?目前的结构是什么样的?

Yeah. And even if you didn't open source it and even if you just used a crate across different teams, that is still a challenge. Do you have a monorepo? What does the structure look like right now?

Speaker 1

是的,我们确实使用的是单体仓库。我们有各种用于服务等方面的独立仓库,但Rust的核心代码以及所有基于它的客户端应用都在一个单体仓库中,这为我们带来了一些构建和发布方面的优势,比如你不需要引入其他仓库来保持所有内容的更新,所有东西都在一个地方。但正如你所说,这也意味着合并冲突可能会成为一个问题,所有依赖你正在开发内容的其他部分都会受到影响。

Yeah. So it is it is a monorepo. We have I mean, we have various repos for for services and things like that, but the Rust core itself and all of the client apps built on it is a monorepo, which which gives us some benefits from, you know, sort of a build and release avenue, right, where everything you don't have to bring in other, you know, repos and so forth to keep everything up to date. It's all in one place. But like you said, that means that, you know, you know, merge conflicts can be a problem and all these different things that are reliant on what you're working on.

Speaker 1

这确实挺棘手的,尤其是对于我们团队所处的位置来说,我们基本上处于整个技术栈的最底层。当我们做出更改时,往往会引发非常显著的连锁反应。你就会面临这样的挑战:我们该如何管理这些变更?对吧?我们的团队是否要告诉使用这些代码的团队,嘿,你需要注意这些变更?

And that's that's tricky, especially from, you know, a team sitting where we do kind of at the very bottom of the the whole stack. You know, when we make a change, there tends to be a very significant ripple effect that you know? And you get into challenges like, how do we manage that? Right? Does our team you know, if you have code that depends on that, do we just tell you, hey.

Speaker 1

我们会打破现状,你需要准备好与我们合作来完成新的工作,或者我们要帮你修复它吗?诸如此类的问题还有很多。而且随着你的发展,有很多沟通需要进行。你知道的,比如你谈到《人月神话》这个概念,对吧?就像往一个项目里再加两个人,并不会多带来相当于两个人的工作量,对吧?

We're gonna break this and you need to be ready to work with us to do the new thing, or do we fix it for you? You know, and so forth. And and there can be a lot of communication that needs to occur as you grow. And and, you know, you talk about, like, the mythical man month, you know, concept, right, of, like, throwing two more people onto a project does not give you two more people's worth of time. Right?

Speaker 1

你会有额外的沟通成本。这些新增的人之间以及他们与其他人之间会创建出许多新的沟通渠道,等等。这会在每一个环节考验你的流程、组织结构以及代码架构。所以当你拥有数百名开发者,有时他们正在处理完全不同的事情时,对吧?甚至已经不是密码管理的概念了。

You have extra communication. There's all these new channels that have been created between those people and the other people and so forth, and it will test your processes and your org structure and your code architecture, you know, at every turn. And so when you get to hundreds of developers working on sometimes completely different, you know, things. Right? They're not even password management concepts.

Speaker 1

他们可能只是与‘密钥’相关,对吧?比如1Password中的SSH代理。嗯,这确实与某种‘密钥’有关,但它与密码管理器中的配置文件或设置之类的东西完全无关。因此,你可能会遇到一些具有挑战性的情况,需要协调完全不同的功能团队之间的底层框架。

They are you know, they may be related to secrets. Right? Like the SSH agent that 1Password 1Password has. Well, that's related to some amount of secret, but it is not at all related, you know, to profiles or settings in the password manager or things like that. So you can get into, you know, challenging situations where you're trying to coordinate underlying frameworks across completely different, you know, feature teams.

Speaker 1

是的,这种情况有时候确实会带来问题,也肯定会减慢进度,但当你从这些经验中学习时,它也会变成一种优势。

And, yeah, that's that's problematic at times, and it definitely can slow things down, but it also becomes a strength when you're learning from those things.

Speaker 0

是的。我们来谈谈规模吧,因为人们喜欢数字。你能分享一些关于代码量、使用Rust的开发人员数量以及维护的crate数量等比较有趣的数字吗?

Yeah. Let's talk scale because people like numbers. Can can you share some of the, let's say, I would say more interesting numbers about the code size and the number of people working with Rust and and crates maintained and so on?

Speaker 1

是的。我们前几天刚查看了一下,核心代码库中跨各个crate的Rust代码大约有50万到60万行。我想我们的内部crate加上依赖项接近600个。所以这是一个相当庞大的代码库,对吧?

Yeah. So we are I think I just looked the other day, and we were at, like, five or 600,000 lines of Rust in the core across, like, crates. I think we're just shy of 600 crates internal plus dependencies. So it's it's a pretty big code base. Right?

Speaker 1

就像我说的,这个核心代码库涵盖了我们尽可能多地用Rust实现的业务逻辑。我不太清楚所有代码的具体分布情况,因为当你实现一个功能时,你还需要在原生客户端中也实现它,对吧?所以每个功能都会涉及一些Swift、Kotlin和TypeScript等不同技术。所以我可以说

And like I said, that that core makes up as much of the business logic as we can get it to. So I don't know the exact spread of all of it because, you know, when you're implementing a feature, you have to also implement it in the native clients. Right? So some amount you know, every feature is gonna have some Swift and and some Kotlin and TypeScript and all these different things. So I would say

Speaker 0

你知道数据管道会有多让人头疼,对吧?我经常听到客户抱怨他们的团队将不同的工具耦合在一起,成本飙升,而团队却越来越沮丧。这时候Infineon就派上用场了。你们中有些人可能记得我们之前邀请过Infineon的DEP来参加节目,他们的平台Fluvio完全是用Rust构建的,这立刻引起了我的注意。

You know how frustrating data pipelines can get. Right? I hear from customers all the time about their teams coupling together different tools, watching costs skyrocket while their teams get increasingly frustrated. And that's where Infineon comes in. Some of you might remember that we had DEP from Infineon on the show a while back and their platform Fluevio is built entirely in Rust, which immediately caught my attention.

Speaker 0

让我印象深刻的是他们如何将一切简化为一个可组合的系统。他们有带状态的数据流操作符,可以让你在数据流中直接进行数据转换,构建出链式调用的带状态服务,这意味着你再也不需要在不同的工具之间来回切换。而且性能也非常出色。我们说的是,在普通硬件上就能实现每秒数百兆字节的吞吐量,延迟只有几毫秒。空闲时内存占用也只有大约50兆字节。

What stood out to me is how they've simplified everything into a single composable system. Their stateful data flow operators let you transform data right in the stream and build daisy chained stateful services, which means no more jumping between different tools. And the performance is no joke. We're talking hundreds of megabytes of throughput on commodity hardware with just milliseconds of latency. It only uses about 50 megabytes of RAM when idle.

Speaker 0

开发体验也非常棒。他们提供了清晰的API和直观的命令行界面。而且从我个人经验来说,无论你有什么问题,DEP的响应总是非常及时。这种支持真的能带来很大的不同。如果你正在构建任何需要实时数据处理的应用,比如交易平台、欺诈检测系统或游戏数据分析,我建议你一定要看看这个。而且因为你是这个播客的听众,现在正值我们的节目季期间,你可以享受专属折扣。

And the developer experience is great as well. They have a clean API and intuitive CLI and speaking from experience, DEP is always super responsive whenever you have questions. That kind of support makes all the difference. If you're building anything with real time data needs, may it be trading platforms, fraud detection or gaming analytics, I think you'll want to check this out. And because you listen to this podcast, you can get an exclusive discount right now during our current season.

Speaker 0

只需访问 infineon.com/rustinprod,并在预约演示时提及我们的节目。地址是 infineon.com/rustinprod。

Just head to infineon.com/rustinprod and mention our show when you book your demo. That's infineon.com/rustinprod.

Speaker 1

你知道,然后你还有服务器端的工作,而并非我们所有的服务器端工作都是用 Rust 完成的。服务器端有很多是用 Go 写的。所以我会说我们大概有 50% 的新代码是用 Rust 编写的,但它肯定还分布在所有其他语言之间。一个端到端功能的开发通常会涉及 Go、Rust、Swift、Kotlin 和 TypeScript,可能 CLI 端还会用到 Go,等等。因此,这里面涉及的内容相当多。

You know, and then you got server side stuff, which not all of our server side stuff is in in Rust. There's a lot of Go on the server side. So I would say probably 50% of everything new that we write is in Rust, but it's definitely spread across all those other things. You know, writing an end to end feature will involve Go and Rust and Swift and Kotlin and TypeScript and possibly Go on the CLI side and so forth. So there's there's quite a bit that goes into that.

Speaker 1

但我想我们目前大概有几百名开发者,他们分布在 1Password 以及像 Collide、Passage、Trellica 等各类产品中工作。但我想大概有 100 人左右,他们大量使用 Rust,或者至少有一半以上的工作是用 Rust 完成的。当然,这只是个大概的估计。

But there's there's probably I think we have a couple 100 developers now working across all the different products that 1Password and, you know, Collide and Passage and Trellica and so forth have. But we probably have, I don't know, I'd say a 100 people that work pretty heavily in Rust or or or maybe 50% or more in Rust, something like that. But that that's definitely a bit of a guess.

Speaker 0

太棒了。目前哪个 FFI 桥接用起来最不顺手?现在最让你头疼的是什么?

Awesome. Which FFI bridge works the least well for you right now? Like, what gives you the most headaches at the moment?

Speaker 1

这要看情况。我认为就实际的 FFI 来说,最具挑战性的可能是 Android,有时候会有点棘手,尤其是 Android 生态系统有些不同。我们的产品最初是作为 macOS 应用构建的,所以我感觉里面还保留了一些苹果产品的基因。我们尝试将这些扩展到所有不同的平台,并让它们都能良好运行。

It depends. I think as far as the actual FFI goes, the most challenging ones are probably well, I guess Android can be a little bit tricky sometimes, you know, especially just Android. The ecosystem's a little bit different. You know, we were built originally as a macOS app. And so I think there's still a little bit of that sort of, you know, Apple product DNA built in, which, you know, we we've tried to spread to all these different platforms and make everything work equally well.

Speaker 1

但我确定里面肯定还残留着一些这样的特性。另外,WASM 的边界也可能比较困难。在一年前我还不了解 WASM。对,我想我之前几乎从未真正接触过它。

But I'm sure there's still a little bit of that in there. And then the the WASM boundaries can be tough. I didn't know anything about WASM until about a year ago. Right? I don't think I'd ever really touched it at all.

Speaker 1

我听说过它,但对其一无所知。后来才发现一些小细节,比如 WASM 中好像没有内置的时钟之类的东西。所以你必须伪造所有这些你以前常用的时间相关功能。当你有一些基于 FFI 的原生客户端通信机制,而它们在 WASM 中无法正常工作时,这就会带来一些挑战。我们最终不得不做了很多抽象层。

I'd heard of it and knew nothing about it. And then you find out little things like the I think there's, like, no built in clock in WASM or something like that. So you're, like, faking all these time based things that you used to do. And so that can be a little bit tough when you have concepts baked into how the native clients communicate across the FFI that just don't work in WASM. And we end up with a lot of abstractions.

Speaker 1

比如,Rust 中有 Send 和 Sync trait。但我们还创建了 MaybeSend 和 MaybeSync trait,用来处理不同平台之间单线程或多线程的情况。说实话,WASM 的边界可能是最难处理的部分。

Like, we have you know, there's send and sync traits in REST. But we have a maybe send and maybe sync trait that handles, you know, four people translating between else is gonna be single threaded or multithreaded and so forth. And so so the WASM boundaries are probably the toughest, to be honest.

Speaker 0

明白了。这个 Baby Send 和 Maybe Sync 听起来挺有意思。那是不是也可以叫 ?Send 和 ?Sync?

Okay. Yeah. The baby send and maybe sync sounds interesting. Wouldn't that be a question mark send and question mark sync?

Speaker 1

我觉得可以。是的。我想我们这样做的方式是,因为我们希望代码能在不同平台之间复用。对吧?但它们的行为可能不会完全一样。

I think it it could be. Yeah. I think what we have so the way we've broken this out, right, is because we want, you know, code to be reusable across platforms. Right? But it may not necessarily work quite the same.

Speaker 1

比如说对于密码密钥或者自动填充功能。这种情况在iOS上的实现方式与Android、Windows或其他系统完全不同。因此,这些功能有各种不同的实现方式,但你又想执行相同的操作流程。只是底层的调用方式,比如系统调用之类的,当你需要调用操作系统时,它们的运作方式各不相同。或者,有些操作你必须在特定的时机执行。

Let's say for pass keys or, you know, or autofill. Like, that happens completely differently on iOS than it does on Android than it does on, you know, Windows or wherever. And so there's all these different implementations, but you wanna do the same process. It's just that all the underlying calls, you know, there may be syscalls or things like that where you're reaching back out into the OS, they work different. Or, you know, some of them, you have to do it in the moment.

Speaker 1

有些操作,你必须在解锁设备时触发某个操作,或者其他类似的情况。我们尝试的做法是,为每个平台分别设置FFI(外部功能接口)。然后我们有一个应用层,可以被多个平台共享使用同一个crate。应用层会调用服务层。而真正的功能实现是在服务层完成的。

Some of them, you have to seed some operation at unlock, you know, or whatever. And so what we try to do is we have these you know, we have FFIs by platform. And then we have, like, an app level where you could have multiple platforms that use the same app level crate. But then what that does is that reaches out to services. And the service level is where all of your actual functionality comes in.

Speaker 1

比如同步功能,有一个专门处理同步的服务,还有一个不同的服务处理自动填充,以此类推。这些服务再调用底层的具体实现。我们的做法是定义一个trait,比如假设是密码密钥之类的功能,然后在下面具体实现获取密码密钥的操作。

For example, sync. There is a service that handles sync, and there's, you know, a different service that handles autofill and so forth. And then those reach out into underlying implementations of things. And so what we do is we try and make a trait that is like, okay, here is, you know, let's say, I don't know, pass keys or something like that. And then underneath that, it's like, alright, get the pass keys.

Speaker 1

但再往下一层,就要考虑我们到底需要获取什么数据?我们什么时候获取这些数据?数据是如何提供的?是否需要从Enclave或者操作系统之类的组件中获取数据?

But then below that, it's like, well, what do we need to get? Which data are we getting? When are we getting this? You know, how is it being provided? Do we need to get anything from, you know, the Enclave or the operating system or whatever it is?

Speaker 1

这些具体实现是由各个平台完成的,这为我们构建系统提供了一定的灵活性。但这也意味着,如果我们正在做的是一个已经构建并使用了四五年之久的完全异步的功能,那该怎么办?我们一直在使用它,比如我们为此启动了大量的线程,或者必须在后台任务中运行它等等。

And those get implemented by platform. And that gives us a little bit of flexibility into how we build up things. But what that means is if I'm doing something that is generally you know, we have built this and have used it, you know, let's say, four or five years now completely async. Right? And we've been using you know, we spin up a ton of threads to do this thing or whatever, or it's gotta be on a background task or something like that.

Speaker 1

但现在在Wasm中可能就无法正常运行了。因此,我觉得我们可能通过引入Send和Sync这两个trait来解决这个问题,确保这些功能可以继续运行。这在整个系统中都成为一个很大的挑战,对吧?

Well, now maybe that doesn't work in Wasa. And so I think maybe send and maybe sync have been our easy traits to kind of layer in to be like, alright. Put this on there to make sure, you know, we can sort of keep these things moving forward. And that and that becomes a big challenge throughout everything. Right?

Speaker 1

当你手头有50万行Rust代码,现在想在Wasm中运行,这和从零开始构建Wasm支持是完全不同的。我们本可以采用不同的方式实现,但目前有数百个功能分布在十几个产品中使用这些代码,要回头重构它们可能并不划算,我们也没有那么多时间。所以,我们可能还有其他方式可以更好地利用这些x(或者他们叫什么),我觉得这些可能只是临时的解决方案。

When you've got, you know, 500,000 lines of Rust and now you're trying to build in Wasm, that's a lot different than we're starting from scratch and building in Wasm support. Right? We could have done things probably a lot differently, but there are hundreds of features across, you know, a dozen products or whatever that are trying to use this stuff and going back and refactoring them maybe just doesn't doesn't add up right now, and we don't have time for that. And so there are probably other ways we could use those x or whatever they call them to to better better use. I think these are probably our temporary temporary solutions.

Speaker 0

我完全理解你的意思,因为到了某个阶段你终究还是得交付产品,这种做法就像是一个实用主义的解决方案。很多人忽略的一点是,这些应用最终需要发布更新,如果引入破坏性变更并不容易,因为它们可能已经被应用的其他部分所使用。所以我想问的另一个问题是,你们有没有一个指导原则来保持核心Rust代码是同步的?异步部分到底深入到什么程度?在什么时候停止使用异步,转而使用自己的同步模块?你们有没有这样的区分?或者说,在你们的项目规模或工程背景下,这种区分是否还有意义?

But I fully get it because at some point, you also need to ship things, and this seems like an escape hatch that kind of was a pragmatic approach to solving this problem. What a lot of people forget is that these are apps that eventually need releases to change or they if they have breaking changes, then it's not that easy because they might be used in other parts of the application. So the other thing I wondered was, is there a guideline for keeping the core synchronous rust? How deep does the async part go and at one at what point do you stop using async and do you start having your own little, say, domain, which is sync? Is there such a differentiation, or would you say that doesn't make any sense at your scale or for the project you do?

Speaker 1

在某些场景下这样做可能是有意义的,但我并不确定我们真的这么做了。实际上,从底层开始就非常依赖异步。比如,客户端向核心发起请求的方式,就是通过FFI进行调用,而FFI本质上就是异步的,对吧?

You know, it might make sense in some places. I don't know that we really do it much, though. It's definitely pretty async down to the root of things. I mean, our our the way our requests from the client into the core work is, you know, you make this request over the FFI, which is sort of inherently async. Right?

Speaker 1

因为FFI并不是那种像HTTP协议中你发送请求就会收到响应的API。我们的方式是,前端通过FFI发送一个请求到核心,FFI会保留一个发送器(sender),然后将请求交给一个监听接收器(receiver)的线程。这个线程会分发调用任务,处理这些请求并执行相关逻辑,最后返回结果。我们处理的方式是,前端提供一个回调函数,当请求处理完成后,这个回调会被调用,并将结果数据作为参数传入。

Because that that's not a an API where you're way you know, it's not baked into, like, the HTTP protocol where you're gonna get a response and Right. Blah blah blah. So you you send us you sort of send this request into the core over the FFI, And then what the core does is it it, that FFI holds on to a sender, and it hands off that request to a thread that is watching the receiver. And that dispatches invocations, you know, these requests that do the work and handle the type process and blah blah blah and then come back. And we you know, the way that we handle that is the front end sends in a callback that once the request is done processing, that invocation dispatch loop executes the callback with the resulting data as an input to that callback.

Speaker 1

这样,客户端这边就处理了一个注册表,记录了我发起的所有请求以及相应的标识符。因此当回调函数被执行的时候,我可以把它放进本地缓存或者存储中,或者把它插入到某个 React 组件中,不管具体是什么。但整个过程本质上都是异步的。它已经深入到从客户端一直到数据库再返回来的整个流程中。所以我相信有些地方会是这样,就像,嘿。

So that way the client side handles sort of a registry of here are all the requests that I have made and sort of an identifier. So when that callback gets executed, I can put it into my local cache or store or plug it into this React component or whatever it might be. But the whole process is sort of inherently async. It is it is baked into, you know, everything from client side all the way down to the database and back. So I I'm sure there are some things where it's like, hey.

Speaker 1

我们需要做多个操作,并且这些操作需要按顺序同步执行。但它们仍然属于一个异步流程中的小范围操作,就像是异步流程中的一个局部同步的小气泡。

We need to do multiple things, and they need to be synchronous in order. But they're a bit of, like, a bubble that's still within an async, you know, flow end to end.

Speaker 0

你描述的这个回调机制听起来很像 Tokio 中的 Waker。嗯嗯。不过我猜应该是在更高的层次上实现的,比如在数据层的某个层面?

The callback mechanism that you described sounds a lot like the waker in Tokyo. Mhmm. But just on a on a higher level, I would assume, like, on a on a data level somehow?

Speaker 1

没错。是的,它确实有点像那样。我们所做的某种程度上就是如此。我认为这有点像是客户端发起了一个请求,理论上已经完成了,对吧?

Exactly. Yeah. It is kind of like that where the we are it it is sort of yeah. I guess it's like building in our own hand rolled waker in some way of, like, the the client technically sends off this request, and it's done in theory. Right?

Speaker 1

或者说从技术上讲,它已经完成了。但它设置了一个函数,这个函数位于内存中的某个地方,并且它已经把这个位置交给我们了。所以当我们用这些数据去调用这个函数的时候,它又会触发一个新的操作。只是我们在代码中把这两个部分连接在了一起,对吧?

Or or technologically, it is done. But it has set up this function, you know, that is somewhere in memory, and it has handed us off where this thing is. So then when we go call that code with this data, it is now kicking off a new thing. It just so happens that we have in code tied those two pieces together. Right?

Speaker 1

所以它有点像 Waker 的机制,只不过我们并没有真正去‘唤醒’它之类的操作。这个回调的触发本质上是异步的。

So it's it's sort of like the mechanism of a waker except that we're not actually, you know, pulling it or anything like that. It is it is inherently async to when that thing gets called back.

Speaker 0

他是否必须使用不安全代码才能实现这一点?

Did he have to use any unsafe code to pull it off?

Speaker 1

我敢肯定在 FFI(外部函数接口)中有一些不安全的代码,因为 FFI 本身的机制就是如此。我确信在实际进行 FFI 调用的地方,这些调用是被包裹在 unsafe 块中的。另外,我认为在某些地方可能也需要做一些处理,比如我们之前提到的零化内存分配(zeroizing alloc)。我敢肯定在某些地方需要进行封装,以确保那些不由 Rust 分配器管理的内存区域在使用后被置零。但总体来说,这个过程还是相当安全的。

I'm sure in the FFI, there's some you know, just the nature of, you know, how FFI works. I I'm sure the calls across the actual FFI are wrapped in unsafe. And then I think there's probably some of you know, we talked about zeroizing alloc. I'm sure there's some amount of wrapping there to ensure that bytes are flipped to zeros, you know, in things that were not being handled by the Rust allocator. But in general, the process is is fairly safe.

Speaker 1

对吧?你通过 FFI 发起调用,而这个对象带着发送者一起被传了过去,一旦你把所有这些都发送过去,一切都没问题。所有这些都可以安全地完成。而执行实际的回调函数,我想在技术上可能必须用 unsafe 来封装,因为你实际上是在触发一个内存地址。但其中的大部分都基于我们在两边都可以做出的某些保证。

Right? You make the call over the FFI, and because that is holding this object with the sender, once you send that all across, you know, that's fine. Everything there can be done safely. And then executing the actual callback probably technically has to be wrapped and unsafe, I would guess, because you are sort of triggering just memory location. But a lot of that is based on, you know, guarantees that we can make in both both sides of the equation.

Speaker 0

你提到了有 600 个 crate。当我听到这个数字时,我的第一反应是,哇,这也太厉害了吧。你是怎么避免陷入依赖地狱的?你是如何保持所有这些 crate 都保持最新状态的?

So you mentioned 600 crates. And when I heard that number, I was, well, all strong. Yeah. How do you not drown in dependency hell? How do you keep all of these crates up to date?

Speaker 1

是的。我觉得你可能以为我们在这方面已经深陷困境了。不过还好,并不太糟糕。一部分原因是自动化。

Yeah. I think you're assuming we aren't drowning in that. No. It's it's, it's not too bad. I mean so part of it is automation.

Speaker 1

对吧?你知道的,我们要确保运行的各项流程,比如依赖监控、漏洞检测等,保持这些内容的及时更新,确保我们不会运行含有易受攻击依赖项的流水线。同时,如果我们某个依赖项变得不安全,我们要迅速更新它,等等。但除此之外,管理所有这些依赖可能会有点棘手。很多问题其实都源于架构层面,比如我们要确保目录结构清晰合理。

Right? You know, making sure that we're running things to ensure like, we have dependency monitoring for vulnerabilities and stuff like that to keep all that stuff up to date, make sure that we're not you know, we're not passing pipelines that have vulnerable dependencies. And, also, if we have a dependency that has become vulnerable, we're updating it quickly and so forth. But beyond that, it's it can be tricky, you know, to manage all those dependencies. A lot of it just comes with the architecture of, like, let's make sure you know, we have directories.

Speaker 1

对吧?比如说,我们有一个数据目录。在这个数据目录中,你只能导入数据目录中的其他内容,或者是一些安全的第三方依赖,但你不能从服务(services)或应用(apps)等目录中导入任何内容。对吧?我们为这些内容建立了一个内在的层级结构。

Right? So we have, let's say, a data directory. And this data directory, you know, okay, you are allowed to import anything else that's in the data directory or any, you know, third party dependency that's safe, but you can't import anything from services or apps or so forth. Right? And we create a bit of a inherent hierarchy to these things.

Speaker 1

所以很多时候,我们只是确保有明确的规则,比如应用模块(App Crate)可以导入任何它想要的内容,除了 FFI(外部接口)。而 App Crate 只能被 FFI 导入,其他任何模块都不应导入它。这是我们最初级的规则。然后我们再往下看服务模块。

And so a lot of it is just making sure that we have clearly defined, like, app crates cannot or app app crates can really import anything that they want except the FFI. And AppCrate should only be imported by the FFI. No one else should ever import an AppCrate. So there's our first, you know, level. And then we go to services.

Speaker 1

比如说,服务之间可以相互导入,或者导入 App Crate,但其他模块不行。而数据模块则可以做这些操作。对吧?你制定了这些小规则之后,你会发现还有很多情况是这些规则无法覆盖的。

It's like, alright. Services can be imported by each other or AppCrates, but nobody else. And now, you know, data can do this. Right? And you create a little bit of these rules, and then you end up with a ton of things that fall outside of it.

Speaker 1

比如,有些模块可能是用来定义类型、服务客户端,或者各种不同的东西。这时候就会遇到棘手的问题:如果我们有一个服务客户端,谁可以使用它?对吧?任何人都能从任何地方调用它吗?它是否应该与数据模块交互,还是我们应该将它们保持分离?类型又怎么处理?

You know, they may be crates that define types or a server client or all these different things. And that's where you get into the the difficult parts of like, well, if we have a server client, who's allowed to use that? You know? Can anyone call that from anywhere, or should that ever talk to the data, you know, crates, or should we keep those separate inherently? What about types?

Speaker 1

如果我们有一个类型,在服务端是这样定义的,在数据库里也是这样定义的,那我们是否应该复制这个类型?这样 Drift(数据库框架)才能正常工作,这样我们就不用频繁修改两边,或者总是只修改其中一边。所以当你有这么多模块的时候,确实会遇到很多挑战。当然,我们也可以引入更多的自动化机制,但总的来说,简单来说,还是有很多人为的流程在起作用。比如说,我们有不同的团队负责不同的概念。他们不一定负责具体的代码片段。

What if we have a type that is this way on the server and it is also that way in the database? Well, do we wanna duplicate that to let those like, to let Drift be okay so that way we're not, you know, modifying both all the time or or one all the time? So you definitely get into challenges that that come with having that many crates. And there's probably more automation that wants to happen, but there's definitely you know, the short answer, I guess, is there's a lot of human process that comes into you know, we have different teams that own different concepts. They don't own necessarily specific bits of code.

Speaker 1

他们可能负责具体代码,但通常来说,他们负责的是某个概念。因为你负责这个概念,所以我们有自动化机制,可以告诉你:这些代码确实涉及了这个概念。或者很多时候,是很多人会说:这个应该由某某团队来审核。

They may, but in general, they own concepts. And because you're owning that concept, we have automation, you know, that will say, okay. These bits of code definitely touch that concept. Or just a lot of people going, okay. This should probably be reviewed by such and such team or so forth.

Speaker 1

我们要确保所有的东西尽可能干净。在代码审查时,我们会检查:这些导入顺序合理吗?我们会发现一些情况,比如他们在某个模型中实现了某些功能,但实际上并不需要放在那里,因为只有一个地方使用它。

And just making sure that we keep everything as clean as possible. And and that we are when we do code review, we're looking at it to go, does this order of imports make sense? You know? And and we'll have things it's like, oh, they implemented this on some model, but it doesn't need to be there. It was only being consumed in one place.

Speaker 1

那我们就把这些内容直接内联进去,把那个模块删掉,整个模型概念就直接内联到它被使用的地方。也许将来我们会发现,其他地方也需要使用它,那到时候再说。

So let's just inline all of that. Let's get rid of that crate, you know, that whole model concept. Let's just inline it right where it was. And then we may find out in the future, oh, well, now somewhere else wants to use it. Okay.

Speaker 1

我们把它拿出来,再放回模型中,然后我们就这样做。对吧?这样是可以的。我们要避免出现‘以后可能还需要它’这样的想法,因为这正是crates真正变成一个问题的时候。你看,我们把某些东西放进新的crate里,是因为我们可能在别的地方还需要它。

Let's pull it back out and put it back into the model and we'll do that. You know? And that's okay. You know, we wanna avoid the like, well, we might need it in the future because that's when crates really become a problem. You know, we put it in this new crate because we might need it somewhere else.

Speaker 1

我们先不要那样做。让我们先保持代码简洁,直到确实需要在别的地方使用它,然后再处理把它提取出来的事情。这才是真正避免crates到处泛滥的唯一办法。

Let's not do that. Let's just enlighten until we know we need it somewhere else, and then we'll deal with pulling it out. And that's really the only way that, you know, you kind of bake in avoidance of crates just proliferating everywhere.

Speaker 0

听起来你把crates当成了kettle(水壶)一样对待。我很想知道,Rust生态系统在这方面提供了多少帮助,又有多少工作仍然需要手动完成?比如说,有Cargo Deny这样的工具。我不太清楚,除了Clippy之外,你有没有特别喜欢使用的其他工具?

It sounds like you're treating crates like kettle. I wonder how much the Rust ecosystem helps with that and how much of that is still manual because there are tools like Cargo Deny, for example. I don't know. Do you have any any tools that you like outside of, say, Clippy that you prefer?

Speaker 1

是的,我们这里大量使用了Clippy。当然也用到了cargo deny。我们会确保,比如说,如果是FFI crate,你只能引入某些特定的内容;如果是应用,就不应该引入某些内容,等等。总的来说,我们可能还需要比现在更多的自动化工具。

Yeah. We a lot of Clippy here. Definitely cargo deny as well. Make sure that, you know, again, that, you know, if it's an FFI crate, you should only be importing certain things, or if it's an app, you shouldn't be importing certain things or so forth. There's again, it probably wants more automation than we have.

Speaker 1

其中很多其实都归结为代码架构的问题。对吧?如果我们确保数据层是自包含的,然后确保FFI到应用再到服务的流程也是自包含的,那么剩下的部分就都是特定领域的内容了。至少在我们能避免的地方,我们不会创建全局性的东西。

A lot of it gets is just the code architecture. Right? If we make sure that the data layer is self contained and then we make sure FFI to app to service is a self contained flow, well, everything else then becomes domain specific. Right? We're not creating global things beyond that, wherever we can avoid it, at least.

Speaker 1

这样的话,如果你所在的团队负责的是自动填充功能,你就可以以规定的方式使用数据层,然后把你所有的代码导入到一个服务中,这个服务再进入应用,最后进入FFI。中间的这些部分,你可以自由发挥。如果你造成了循环依赖或者其他问题,那就是你自己的责任。或者如果你在这些组件之间构建了糟糕的架构,那你就要自己负责维护它。

So that way, if your team, let's say, works on autofill, you get to use the data layer in prescribed ways, And then you import all your stuff into a service, which goes into an app, which goes into the FFI. Anything in between there, that's up to you. You know? If you create a circular dependency or whatever, that's your problem. Or if you create a bad architecture between these things, well, you have to own that.

Speaker 1

对吧?你必须维护它。所以你会自己发现问题,并通常自行修复。因此,很多问题其实都归结为这种架构设计:保持顶层自包含,保持底层自包含,中间部分则根据功能或领域进行划分。这样,这些有明确边界的领域就能各自独立地运作。

Right? You've gotta maintain that. So you're going to find the problems with that and and generally fix it yourself. And so a lot of it is just that architecture of, like, keep the top layer contained, keep the bottom layer contained, and then everything in the middle is feature specific or domain specific. So that way, those bounded domains are dealing with themselves.

Speaker 1

还有一些其他方面也体现了这种思路。比如,我们有一个foundation目录,专门处理与操作系统相关的调用。所有特定于Windows的内容都有自己的区域,等等。我们在这些方面也做了一些类似的工作,比如由平台开发团队来维护这些部分。

And and there's a couple other things that that have this. Like, we have a foundation directory, which deals with OS specific calls. Mean, You anything that's Windows specific has its own area and so forth. So there are a few other things we do like that where it's like, okay. That is maintained by this platform advancement team.

Speaker 1

如果你需要对这些内容进行修改,就需要与他们合作完成。而你只需要使用这些已经封装好的内容。在你自己的有界领域内,任何crates之间的交织都必须在你被指定的范围内完成。当然,正如你所说的,我们确实也依赖一些自动化工具,比如cargo deny、clippy等,来帮助我们尽可能地清理这些问题。但很多时候,这仍然需要大量人工参与。

And if you need changes there, you work with them to make those changes. But you are just consuming those things. And any, you know, interweaving of crates that you do within your bounded domain needs to happen within the, you know, box you were provided. But it it definitely does rely on a little bit of that automation, like you said, of, cargo denying, clippy, and so forth to ensure that we are cleaning that up where we can. But but but it's definitely a manual process, a lot of times.

Speaker 0

我不确定这是不是真的,但我听说1Password在开发环境中使用了Nix。你能稍微谈谈这方面的情况吗?

I'm not sure if it's true, but I heard that 1Password uses Nix for their development environment. Can you say a few words about that?

Speaker 1

是的。我们确实大量使用了NICs。至少在核心方面,它为我们很多构建流程提供了支持。此外,我们还用它来管理核心方面的工具链。这非常方便,因为当你在多个平台上工作时,你需要处理大量的工具链相关的内容。

Yeah. So we we definitely have a lot of NICs usage. So it is it powers our our on the core side, at least, it powers a lot of our build processes and stuff like that. And then we use it to manage our tool chains on the the core side as well. And that has been really, really nice because there is so much, you know, tool chain stuff that you need when you're working across all these platforms.

Speaker 1

比如说,你可能需要各种Linux专用的工具,也需要Mac专用的工具,以及让Android Studio能够运行的各种组件,还有各种内部工具。没错,我们有1Password的命令行工具(CLI),我们用它来处理一些事情,还有Type Share工具,它也是一个CLI工具。每当我们要对Type Share进行更新时,这些更新都需要纳入开发人员的工具链中。

You know, you might need all of these Linux specific tools, and you need these Mac specific tools, and all these things that make Android Studio work. And there's all these different things that come together as well as, you know, internal tools. Right? We have the one password CLI, which we use for things, and the type share tool, which is a CLI tool that is used for things. And so whenever we make updates to type share, that needs to become part of developers' tool chains.

Speaker 1

我们使用NICs来管理所有这些工具。这样,一旦有更新,只要我拉取主分支(main),而主分支上的flake发生了变化,我的工具链就会自动更新。我自己完全不需要干预。当然,我需要多等几秒钟来下载所有内容并重新构建工具链。但从那之后,我就不用再操心了。

And so we use NICS to manage all of that. And that way, whenever there's an update, if I pull main and that next flake has changed on main, well, my tool chain just gets updated. I don't know the difference. You know, I have to wait a few seconds for it to to pull everything in and build the tool chain. But from that point, I don't care.

Speaker 1

还有一个叫Durenv的工具,它基本上可以自动设置某个目录,使其使用Knix Flake作为该目录的工具链。因此我不需要担心版本管理的问题。我也无需担心,我是不是很久以前运行了安装脚本,而之后有人又添加了新的内容?这不再是我的问题,Nick会自动处理好所有这些事情。

And and there's the, Durenv tool, which basically sets up that directory to automatically use the Knix Flake as your tool chain for that directory. So I don't have to worry about version management. I don't have to worry about, you know, did I run the install script too long ago and somebody added something to it since then? That's not my problem. Nick's just handles all of that.

Speaker 1

这种体验非常棒。当然,你需要掌握一些特定的知识,比如关于Nick的知识,关于flake的语言,以及其他各种细节,可能需要花点时间去摸索和理解到底发生了什么。但总的来说,它非常强大。我们公司有一个概念,我知道其他一些公司也有类似的做法,我们称之为‘公会’(guilds),也就是跨团队对某个主题感兴趣的人组成的小组,比如Rust公会。

And it's been it's been really amazing. I mean, there's there's a bit of knowledge, you know, Nick's specific knowledge, you know, flakes in the language and all these different things can require a little bit of a little bit of playing with to really understand what's happening, but but it's been really powerful. And it's helped we have a concept here, which I know some other companies have as well. We call them guilds of, like, cross team interest in a topic. So, like, there is a Rust guild.

Speaker 1

是的,我们不同团队都有开发人员参与。比如说,我的团队可能有四位Rust开发人员,还有其他开发人员。而自动填充团队也有几位Rust开发人员,其他团队也是如此。但我们之间可能并没有太多直接的协作。

Right? And we have all the developers on different teams. Like, my team has, let's say, four Rust developers and then some other developers. But then the autofill team has a couple Rust developers and this team and so forth. And we don't maybe collaborate all that directly.

Speaker 1

但现在在Rust公会里,我们可以专门讨论Rust相关的话题,不需要担心与其他系统的交互问题。我们只讨论如何编写Rust代码,分享一些关于Rust的有趣文章等等。我们也有一个关于Knicks的类似公会。

But now in the Rust Guild, we can just talk Rust. We don't worry about, you know, interactions with other things. We just talk about how do we wanna write Rust? Here's an interesting article about Rust, so forth. And we have one of those for Knicks as well.

Speaker 1

比如说,负责构建和发布的人员在那个群里,我团队中的一些也是Knicks爱好者的成员也在里面。这帮助我们确保,即使某位负责工具链的人在处理某个问题时遇到了困难,比如‘我搞不定这个’,现在还有一群人平时就喜欢研究这些,或者在他们家里也用Knicks之类的。他们可以说,‘哦,我在家里做过这个’,这样我们就能互相补充知识,提升各个团队的能力,帮助大家提升技能。

So, know, the build and release people are in there and some of the people from my team who are all just kind of Knicks fans are in there and so forth. And that helps us to make sure that, you know, someone who maybe owns the tool chain is working on something, you know, like, hey. I couldn't figure out how to do this. Well, now there's a bunch of other people who just work on this in their spare time or, you know, have their home set up in Knicks and so forth. Like, oh, I've done that here, and we can we can sort of augment the knowledge on various teams and and really help to skill people up.

Speaker 1

比如我们的Rust公会,我们组织了一个Rust学习小组。我记得上一次看的时候,大概有160人参加。大家在一起学习Rust书籍,向公司内部的Rust专家学习,并一起做项目,这些活动帮助我们显著提升了各个领域(包括Next)的整体技能水平。

Like, the Rust Guild, we run a a Rust study group that has I think we had, like, a 160 people in it or something like that the last time I looked. And so it's people, you know, going through the book together and learning from some of the experts that work here in Rust and then working on projects together and all these different things, and it helps us to really kind of, like, raise the floor of skills in all these different domains, including Next.

Speaker 0

关于外部依赖,你们有没有使用过生态系统中哪些流行的crates?如果有,可以提一下,任何内容都可以。

About the external dependencies. So any of of the popular crates, are there things that that you use from the ecosystem that you kinda wanted to mention? It could be anything, really.

Speaker 1

是的。就像我刚才说的,我们经常使用东京(Tokyo),并且使用整个东京生态系统。对吧?我们用东京本身来处理频道(channels)和各种不同的功能。我们还用Axiom来提供各种服务,等等。

Yeah. I mean, so, obviously, like I said, we use Tokyo a lot, and we use the whole Tokyo ecosystem. Right? We're using Tokyo itself for, you know, channels and all these different things. We use Axiom for various services and so forth.

Speaker 1

塔(Tower)中间件非常非常有用,因为它让我们能够共享一些东西。比如说,如果我们有一个功能完全独立于另一个功能,但它们可以创建一个中间件来处理认证之类的功能。太棒了,现在另一个功能也可以使用它了,因为我们采用了相同的认证方式。这大大促进了代码的共享。

Tower, you know, the tower middleware is really, really helpful because it allows us to share things. You know, if we have one, again, feature that's totally independent from some other feature, but if they create a middleware that handles, oh, this handles authentication. Great. Well, now this one can use it too because we auth the same way. And so it allows a lot of of sharing there.

Speaker 1

追踪(Tracing)是非常关键的。显然,同样因为有这么多功能和这么多层级,使用追踪可以让我们清楚地看到,我是否做了一些让整个系统变慢的事情,或者我的性能瓶颈出现在哪里等等。所以这方面非常棒。Sare day(可能指某个工具或模块)显然也很关键,对吧?

Tracing is really critical. Obviously, again, having so many features and so many layers using tracing gives us a lot of visibility into, you know, did I make something that just slowed everything down, or where is my slowdown occurring, you know, and so forth. So that's great. Sare day is obviously pretty critical as well. Right?

Speaker 1

我们需要做很多序列化和反序列化的工作,比如从服务器接收数据等等。这非常有用。然后我们还有一些内部的 crate(库),就像我刚才提到的 type-share、parsers 等等。我知道的其他常用库包括 Rust Q lite,它对 SQLite 的交互非常重要,这让很多事情变得更容易了。

We have to do a lot of serializing and deserializing, you know, coming in from the server and and so forth. So that's really helpful. And then some of our internal crates, right, like I mentioned, like type share, PASK ERS, and so forth. The only other ones that I know of that come up a lot are like, Rust Q lite is important for for SQLite interaction. That makes things a lot easier.

Speaker 1

还有测试方面的东西,比如 mock-all 很不错。我们使用 cool-asserts。我们这里还有一些开发者开发了公开的 crate,我们也经常使用,这些库非常好。

And then testing things. Right? Like, mock all is good. Cool asserts, we use. We also have some developers here who have public crates that we use that are nice.

Speaker 1

比如我们的一位开发者,我想他是负责 Neon 项目的,它主要是处理 Electron 应用中的 Node.js 绑定。Nathan West,他在这里,开发了一个叫 NOM Supreme 的库,这是一个 Nope NOM 的辅助库,非常酷。我个人非常喜欢 NOM Supreme,等等。

Like, one of our developers, I think, works on Neon, which handles, like, Node. Js bindings for the Electron apps. Nathan West, who's here, made a NOM Supreme, which is a Nope. NOM helper library, which is really cool. I really like NOM Supreme and so forth.

Speaker 1

所以有很多非常酷的东西。我的一位同事 Ivan 也有一个叫做 Crane 的项目,它可以帮助处理混合项目。虽然我们这里其实并没有使用 Crane,但有趣的是我们会遇到一些开源项目。我们会和其他团队交流。比如我们在 Rustkoff 时就和开发 Zed 编辑器的团队聊过。

And so there's there's a lot of really cool things. One of my teammates, Ivan, also has a project called Crane, which helps with mix projects. And I don't think we actually are using Crane here, but it's funny because we'll come across open source projects. We'll talk to other teams. I mean, we're talking to the team that built the Zed editor when we were at Rustkoff.

Speaker 1

于是我们和他们建立了一些沟通渠道,尝试帮助他们做一些早期测试的工作,而他们当时正在使用 Crane 来构建 Zen。当时我们就觉得,哦,这真有意思,原来是我们这边的人做的东西。所以看到整个生态系统逐渐融合在一起,这种感觉真的很棒。没错。

And, you know, so we we opened up some communication with them trying to, you know, help kinda beta test some stuff that they were working on, and they were using Crane to build, Zen. And so was like, oh, that's funny. That's that's something that one the people here made. And so so it's kinda neat seeing the ecosystem come together. But Yeah.

Speaker 1

没错。

Yeah.

Speaker 0

完全同意。这种在不同公司之间使用 Rust 所产生的代码共享总是让人感到惊讶。顺便说一句,如果有人想听我们之前提到的那一集,那是几集之前的内容了。这些家伙的工作非常出色。我们无法谈论所有的 crate,但我特别想问你的是 tracing 这个生态系统的相关问题。

Totally. That's always surprising. The code sharing that happens between different companies using gross, that's always very surprising. And by the way, if someone wants to listen to the episode we've said, it's been a couple episodes before, these guys are doing amazing work. We can't talk about all of the crates, but one thing specifically that I wanted to ask you about was the tracing ecosystem of crates.

Speaker 0

具体来说,如果你将 tracing 与 log crate 一起使用,或者使用 tracing 来实现追踪加日志记录,这正是该 crate 非常流行的一种用法。

Specifically, if you use tracing in combination with the log crate or if you use tracing for tracing plus logging, which is a very popular usage of that crate.

Speaker 1

是的。我认为这其实是现在正在发生的事情之一。我的意思是,我们主要用 tracing 来做追踪,主要用于内部性能遥测方面,这方面我们有很多工作在进行。但现在另一个重要方面是,尤其是在我们的云基础设施中,要确保我们的代码库能够兼容各种语言编写的服务。尤其是现在,越来越多的公司加入进来。

Yeah. So that is actually something I think that is coming about now. I mean, we've used tracing primarily for tracing, right, for sort of internal performance telemetry a lot, and we have a lot going on there. But one of the other things now is especially, you know, in our cloud infrastructure, trying to make sure that, you know, we have crates in or crates. We have services in various languages, especially now, you know, that all these other companies are coming into the the fray.

Speaker 1

我们有 Ruby、.NET,以及其他各种语言。因此,我们要确保可观测性不会因为这些语言的不同而受到阻碍。我们有一些中间层的处理机制,比如说处理日志输出,并确保这些日志格式标准化,这样我们就可以统一地进行跨服务的观测,覆盖整个生态系统。对吧?我认为这正是我们现在在做的事情之一,就是使用 tracing 的一个 tracing 订阅者,来确保我们的日志输出符合标准,这样任何 Rust 应用都能以正确的格式输出日志,并确保这些日志能被其他服务所消费。

There's, you know, Ruby and, you know, dot net, I think, and all these other things. And so we want to make sure that our observability is not hindered by that. So we have some, you know, intermediate things that are handling, let's say, logging output and making sure that it is normalized so that we can handle observing, you know, cross service, you know, the whole ecosystem. Right? And so that's something that I think we're actually doing now is using tracing a tracing subscriber to make sure that our log output is you know, meets the the standard essentially so that any given Rust app can can output their their logs in the right format and make sure that they're consumable by these other services.

Speaker 0

你现在有没有特别喜欢或者不喜欢 tracing 的地方?

Are there any things that you specifically like about tracing or you dislike about tracing right now?

Speaker 1

我不太确定。我没有深入参与它的实现工作,所以我应该说,我没有太多特别不喜欢的地方。能够直接跳转到某个函数,然后说,我只需要在这个地方加上 tracing 的宏就可以了,这真的很方便。

I don't know. I didn't work on the implementation of it too much, so I I would say I don't have a lot that I dislike about it. It's really nice to be able to just jump on to, you know, have some function to go. I'll just wrap you know, add the tracing macro to this. Right?

Speaker 1

现在我就能获得关于这部分的数据,我可以非常快速且轻松地对这些内容进行插桩,而且数据会自动添加进来。我能看到我想要的一切。这对我们来说帮助非常大。比如说,我们之前研究过一个问题:当我们执行这些调用时,它们本质上是异步的,但有些调用可能计算密集。比如说,需要遍历一个巨大的列表,只能以这种方式执行。

And now I'm getting data about this, you know, and I can instrument these things very quickly and easily, and it adds in there. And I'm I'm seeing, you know, everything that I want. It's been a huge help to be able to go you know, one of the things we were looking at was, like, when we do these invocations, right, they are sort of inherently async, but you may have invocations that are performance heavy. Right? Something that has to, like, you know, let's say, iterate through a giant list, and it just has to happen that way.

Speaker 1

所以我们有一个阻塞线程池。Tokyo 提供了在阻塞线程池上执行阻塞任务的能力,但你也可以运行异步任务。而异步任务在很多情况下更偏向协作式调度。我们后来遇到了一个问题:我们有数百个这样的调用,那我们怎么知道哪些应该使用阻塞线程池,哪些应该使用异步线程池呢?

So we have a blocking thread pool. You know, Tokyo gives you you can do a blocking task right on this blocking thread pool, but you also have async tasks. And async tasks tend to be more, you know, cooperative in a lot of cases. And so we got down to the point where it was like, you know, we have hundreds of these invocations. Well, how do we know which one should be blocking and should be async?

Speaker 1

如果它有等待操作,它就应该使用异步方式。但在那100个没有 await 的调用中,哪些更适合放在哪个线程池中?我们就可以使用 tracing,逐个将它们从阻塞方式切换到异步方式,做一些简单的语法转换,进行 A/B 测试,然后判断哪个更好。

Right? If it's gotten a weight, it needs to be async. But out of the 100 that maybe don't have an await, which ones are better served on which thread pool? And so we can use tracing and just go through and just literally flip it from blocking to async and, know, do the little yeah, minor, you know, syntax conversions we need to do and just do AB, you know, one to the other and go, okay. Here was this one.

Speaker 1

然后我们就能轻松地遍历所有这些调用。我记得大概是两年前,我做过这样的事情,就是逐个运行每个调用,然后把它们全部切换到另一种方式,看看哪种更快,最后提交了一个 MR,把所有调用都改了。

Here was this one. Oh, it's faster than Let's put it over there. You know? And it makes it really nice to be able to just kinda jump through all these things. I did that, I think it was, I guess, two years ago now, And just ran through every invocation as it was, and then flipped them all to the other one and see which one's faster and had an MR with just everything.

Speaker 1

通过 tracing,我得到了结果,所有的数据都在这里。tracing 真的太棒了。

Here's what came up faster with tracing, and here's all my results. So tracing is, I mean, is incredible.

Speaker 0

这是一个追踪功能非常好的使用场景。另外一个是Tokyo控制台,它也类似。不知道你有没有听说过它,它可以显示Tokyo的状态以及未来执行的任务及其耗时情况。你听说过这个吗?

That's a really nice use case for tracing. The other thing is Tokyo console, which is similar. I don't know if you've heard about it, but it shows you the state of Tokyo and the futuristic executed and how long they take. Did you hear about that?

Speaker 1

是的。Tokyo控制台也非常棒。我想,我们团队里有个人叫Ivan,就是我之前提到的那个在Crane项目上工作的人,我觉得他也是Tokyo的主要维护者之一。Ivan帮助我学到了很多东西。他说,我刚来的时候完全没有任何Rust背景,而Ivan是一位Rust专家。

Yeah. Tokyo console is pretty awesome as well. We have I think Ivan, actually, the one that I mentioned who works on Crane, I think he also is one of the maintainers of Tokyo. But Ivan is has helped me learn a lot. He said, I had no Rust background at all when I got here, and Ivan is a Rust expert.

Speaker 1

除此之外,我们还有一些其他的人才。就像我之前提到的,Nathan也非常厉害,他对Rust的了解非常深入。但过去三年里,我觉得从Ivan那里学到的东西比我之前七、八年加起来还要多,无论我之前做过什么。他经常带我一起看,比如当你进入某个流程并启动了客户端应用,它发起了一个请求,我们分派了一个任务,这个任务可能会触发其他任务,而数据库访问都是异步的。因此,这些请求会形成一个队列,然后会触发一些事件,这些事件又可能触发其他异步任务。

We also we have a few others as well. Like I mentioned, Nathan is absolutely incredible, just the things that they know when it comes to Rust. But the last three years, I feel like I've learned more from Ivan in the last three years than I learned in the prior, you know, seven or eight combined, everything that I did. But, yeah, showing me, you know, when you get through and you you got the the client app running and it makes this request and we're dispatching, you know, this one task, and then that may kick off other tasks and, you know, the database access is all asynchronous. And so there's a queue of these requests, and then there's events that get triggered off of that, which may trigger other async tasks.

Speaker 1

所有这些事情都在同时发生,通过控制台查看这一切,对于了解系统内部的运行情况非常有帮助。比如,到底发生了什么?对吧?我看到一条日志信息显示同步开始,然后又有一条日志显示同步完成。但在那期间,有很多任务被启动,有的慢,有的快,等等。

And so all this stuff is going on and and, you know, looking at all of this stuff in the console is a huge help to get visibility. Like, what's really happening? Right? I, you know, I see a log message just starting sync, and then I see a log message just says sync completed. But inside of that, there were so many tasks that spun up and some were slow and some were fast and so forth.

Speaker 1

所以,就像你说的那样,Tokyo控制台非常适合用来理解那些异步任务(futures)的执行情况。我们使用tracing(追踪)更多是用来观察函数调用。比如,在我们的情况下,调用了某个函数,并且这个函数是被插桩的。

And so, yeah, like you said, Tokyo console is really great for understanding the futures that happened. You know, we're we're used tracing, I think, more for, like, function calls. Right? Like, in our case, at least, like, we called this function. It is instrumented.

Speaker 1

我发现这个函数用了十秒钟。在这十秒里,某个子函数用了——嗯,我想想,10秒确实太长了。那我们假设这个函数用了100毫秒。在这100毫秒内,有三个子函数各用了10毫秒。对吧?

I see this function took ten seconds. And inside of that, this one took well, I guess, 10 would be a long time. Let's say it took a hundred milliseconds. And inside of that, here are three others that took ten milliseconds each. Right?

Speaker 1

通过这种方式,我获得了可视化的信息。但看到那些被触发的异步任务及其耗时,确实能让你更深入地了解系统内部实际发生了什么。对吧?

I get that visibility. But seeing the futures that kicked off and how long those took does really give you another level of visibility into what's really happening under the hood. Right.

Speaker 0

如果我理解正确的话,你们并不是追踪每一个异步任务,而是将它们按逻辑单元进行分组,把那些应该一起执行的任务组合起来,从而获得一些洞察。

If I understand correctly, you don't trace every future, but you kinda group them into logical units, things that make sense to be executed together just to get some insights.

Speaker 1

没错。这也是Tokyo tracing设计得非常好的一个地方,那就是它的spans(时间跨度)。你可以创建span,进入span,执行各种操作。我们在实际中大量使用了这些功能。

Yeah. And that's another thing, I mean, that's really great about the way that the Tokyo tracing is set up is that you have, like, the spans. Right? And you can create spans and enter spans and all these different things. And so we use those pretty heavily.

Speaker 1

在某些特定的场景或代码路径中,可能会追踪单个异步任务。但通常情况下,很多时候我们只是在进入某段代码时,想知道这段代码执行需要多长时间?对吧?我们想知道这里到底发生了什么。因此,并不是每个异步任务都会被追踪。

There are probably scenarios or or code paths where individual futures are traced. But in general, you know, a lot of times, it'll just be when we're going to some block of code, what you know, how long does this take? Right? What what do we what is happening here? And so it's not always every single future.

Speaker 1

这正是我们试图进行监控的部分,对吧?此外,拥有控制台也非常有帮助,但这些跨度(spans)让我们能够对不同的概念进行逻辑分组,就像你刚才说的那样。因此,我可以看到整个跨度耗时多久,以及该跨度中的各个区块分别耗时多久,无论是多个 future 还是一个。我可能并不太关心各个 future 的耗时。

It is it is specifically what we're trying to instrument. Right? And so the having the console as well is is very helpful, but those spans make it nice to have logical grouping, like you said, of of different concepts. And so I can see within the span how long is the whole span taking and then how long are individual blocks of that span taking, whether it's multiple futures or one. I may or may not care, you know, how long the individual futures take.

Speaker 1

对,比如说我有一些 future 执行某个工作单元,这个工作单元是必须完成的,而且没有其他方式可以完成。在这种情况下,我不一定关心这些 future 的具体耗时。但我确实关心这个代码块整体的耗时,这可能帮助我判断,哦,这是一个 VAC,其实它并不需要是一个 VAC。也许现在我们可以对它进行排序,在我们拥有这些数据集的情况下,更合理的做法是花时间提前进行哈希处理,或者把它变成一个 B 树集合(B Tree set)之类的结构,然后进行排序,这样在大多数情况下,当我们执行操作时,通常是在某个位置插入元素。

Right? Let's let's say I have some future that does some unit of work, and that unit of work has to happen, and it there's no way other way to do it. Maybe I don't necessarily care how long those features take. But I do care how long this block takes, and that may me help me, you know, determine, oh, this is a VAC, and it it doesn't need to be a VAC. Maybe now we can order it, and it you know, with the datasets we have, it makes more sense to spend the upfront time hashing this or making it a B Tree set or something like that and ordering it all so that, you know, most often what we're acting on is we're inserting somewhere.

Speaker 1

好的,这会让我们在插入时获得更快的速度,而且通常来说,花时间排序是值得的。所以,是的,这些 spans 确实非常有用。

Okay. This gives us that that speed up on insert, and it's often worth, you know, the time to sort it or something. So, yeah, the the spans are really nice.

Speaker 0

嗯,有些人可能会听到这里,然后心想:我永远也达不到这种熟练程度。他们也许会好奇,每天和大约一百名其他 Rust 开发人员一起在同一个代码库中工作是一种什么样的体验。你看到过哪些模式随着时间推移逐渐演化?代码的复杂度如何?这是人们可以通过自学掌握的东西吗?

Well, some people might listen to this and say, I I will never get to this level of proficiency. And maybe they are curious what it feels like on a day to day to work together with maybe 100 other Rust developers on the same code base. What are some of the, you know, patterns that you see evolve over time? What is the complexity like? Is it a thing that people can, you know, teach themselves?

Speaker 0

有没有什么指导原则?你有没有发现自从你开始使用 Rust 以来,有哪些实践是你认为现在必须遵循的,以及你们在 1Password 所看到的最佳实践是什么?

Are there any guidelines? What are some things that you would say evolved since you started working with Rust that you would say, you should definitely follow this, and these are the best practices that we see at 1Password?

Speaker 1

是的。首先,我刚来公司的时候,面试我的人试图给我看一些 Rust 代码,因为那时我还没接触过 Rust。他们给我看了一些 Rust 代码,大概是实现一个数字感知排序(number aware sort),比如确保在某个列表中 One Password 会出现在正确的位置上,诸如此类的事情,对吧?

Yeah. I mean, so I would say first and foremost, when I got here, when they interviewed me, they tried to show me some Rust code because I had never done it at that point. They showed me some Rust code, and it was essentially a, like, a number aware sort. So making sure that, you know, one password, you know, shows up in the right order in this list or or something like that. Right?

Speaker 1

当时我根本看不懂。虽然我大致能跟上思路,比如它是在尝试做这件事,但它用了这些 chunks,我根本不知道那是什么。接着它又做了一些内存相关的操作,而我之前是写 TypeScript 的,完全没有接触过内存操作。所以我完全不知道发生了什么。

And I could not get through it at the time. Like, I I I wasn't I was generally following. Like, it's trying to do this, but it was using these chunks, I didn't really know what that was. Then it did a little bit of memory stuff, and I had never touched memory coming from Column TypeScript. So I had no clue what was going on.

Speaker 1

幸运的是,他们还是录用了我。我也不知道为什么,但他们确实录用了我。所以过去这三年,就是我学习 Rust 的全部经历。对,那是我第一次接触 Rust。

And luckily, they hired me anyway. I don't know why, but they did. And so, you know, in the last three years is everything that I have learned when it comes to Rust. Right? That's the only time I've ever seen it.

Speaker 1

所以 Rust 是完全可以学会的。当然,我不是一个人在学。我有好几位非常出色的 Rust 老师。就像我刚才提到的,我们有一个 Rust 学习小组,我在第一期就参与了,当时我的同事 Tanner 发起了这个小组。

And so it's definitely something you can pick up. I have not done it alone. Right? I have had multiple teachers who are absolutely incredible when it comes to Rust. And like I mentioned, we had that Rust study group, which is something that I took part in in the first iteration when my coworkers, Tanner, had set it up.

Speaker 1

这个学习小组对我帮助非常大,所以我后来接手了它,并主持了第二期的学习。现在,我们已经把这个小组发展成了一个完整的 Rust 技术小组(guild)。我想说的是,无论什么时候,只要有机会向他人学习,对你都会有非常大的帮助,尤其是在学习 Rust 的过程中,因为你可能来自一些编程语言,其中的很多概念根本不存在。你正在尝试学习的,是一整套全新的东西。

And then it had been so massively helpful to me that I ended up taking it over and running the second iteration of it. And now, you know, we've grown this into this whole Rust guild. So all that to say, anytime you can learn from other people, it will be massively helpful, I think, especially in Rust because you may be coming from languages where the concepts just don't exist. Right? And you're trying to learn all these brand new things.

Speaker 1

所以这确实是一个巨大的帮助。你可以自己学习。现在有很多优质的资源。Rust 社区中有一件特别了不起的事情,就是有很多非常棒的 Rust 书籍都是免费的,对吧?

So that's a huge help. You can learn it on your own. There are a lot of good resources out there now. One of the things that's been really incredible in the Rust community is there's a lot of the books that are amazing books in Rust that are just free. Right?

Speaker 1

比如,Mara 出版的《Rust Atomics and Locks》这本书就是免费的。你可以在互联网上获取它,当然你也可以选择购买。但类似这样的资源还有很多。Rust 官方的那本书也非常棒。

Like, the Rust Atomics and Locks book from Mara is is free. You can get it on the Internet. You can also buy it if you can. But there's so many of these things. The Rust book itself is really great.

Speaker 1

我发现从零开始达到高效开发最难的一点其实是这样的。我今年在 RustConf 上稍微谈过这个话题。我们发现教别人时最大的问题不是学习 Rust 的语法。真正的问题在于,写出好的 Rust 代码需要一定的工程知识,而这些知识可能并不是书本会涵盖的内容,对吧?

One of the hardest things to get from, you know, zero to productive, I found actually, I I spoke at RustConf a bit about this this past year. What we found teaching people is the issue is not learning the Rust syntax. It tends to be that Rust, good Rust, requires a bit of engineering knowledge. And that's not maybe engineering knowledge that the book is covering. Right?

Speaker 1

你我之前也稍微聊过这个话题,对吧?比如,我什么时候应该新建一个 crate?Rust 官方书籍不会告诉你这些。这并不是一个 Rust 的问题。

And you and I talked about this a little bit. Right? Like, how do I know when I make a new crate? Well, the Rust book doesn't I mean, it's not gonna tell you that. That's not really a Rust problem.

Speaker 1

对吧?这是你代码库的问题,是一个工程问题。它往往会暴露出你在其他领域知识的不足。说实话,我自己也没有计算机科学背景。我以前是个建筑工人,在成为开发者之前,还在药店工作过。

Right? That's a your code base problem. It's an engineering problem. It tends to expose your, you know, lack of knowledge in other areas, which, again, I I also have no computer science background. I was a construction worker before, and I worked at, you know, a drugstore before I became a developer.

Speaker 1

所以我对二叉树和排序这些概念完全不了解,老实说,现在也还是不太懂。但 Rust 有一种方式会让你意识到这些知识的欠缺,一开始确实挺难的,但它也能帮助你弥补这些不足,因为它让你清楚地看到自己的知识盲点。而且现在网上有大量你可以学习的资源,但确实需要时间。并不是每个人都有那么多时间,所以这可能会有点困难。

So I had no idea about binary trees and sorting. I I still really don't, to be honest. But it's Rust has a way of bringing those things out in you, which is hard at first, but it also helps you to shore them up because you see where your gaps are. And there is so much information out there that you can learn from, but it does take time. And not everybody has time, So that can be a bit difficult.

Speaker 1

不过,总之我想说的是,你可以自学,但也要尽可能地向他人学习。看看别人的代码,试着去理解它。然后逐渐掌握一些模式,我觉得这主要涉及两个方面:比如,你为什么要对某些东西进行抽象?因为在 Rust 中抽象是非常重要的。

But anyway, that's a long way to say you can learn on your own, but learn from others wherever you can. Look at code, try and understand it. And then getting into patterns, a lot of it has been thinking about two things, I think, heavily. What like, why are you abstracting something? Because abstractions are really big in Rust.

Speaker 1

对吧?就像我之前说的,我们使用 Rust Qlite,但我们封装了每一个事务,以便在调试模式下添加我们想要追踪的计数器。然后我们可能需要封装保存操作,以便在插入一行时增加这个计数器。最终你会得到一层又一层的抽象。如果你不知道自己在看什么,这些抽象会更难理解。

Right? You know, like I said, we use Rust Qlite, but we wrap every transaction so that we add some counter that we want to follow in debug mode. And then we have to wrap, you know, maybe the call to save to increment that counter, right, to insert a row to increment that counter. So you end up with abstractions on abstractions on abstractions. And if you don't know what you're looking at, those are even harder to follow.

Speaker 1

所以要确保你的抽象是有意义的,如果因为某些原因必须设计得复杂,那就要好好地进行文档说明,这是非常关键的。即使是你自己以后要回来看,也要确保你能明白当初为什么要这样设计。这一点真的非常重要。另外,我觉得第二点是确保你不要为了性能而牺牲代码的简洁性。

So making sure that your abstractions make sense, and if they have to be complicated for any reason, document them really well. That's, I mean, critical. Even if you are the one that's gonna come back and read it, make sure you know why you made this subtraction. That's that's really important. And then the second thing, I think, is trying to make sure that you are not driving performance at the cost of simplicity.

Speaker 1

对吧?比如说,我看到这段代码,觉得从技术上讲最快的方式是创建一个一次性通道进行监听,一旦收到消息,就启动一个接收循环,然后进行查找。如果你能用 Vec.find 或者类似的方法实现同样的功能,那就直接这么做吧。

Right? You know, if I look at this and it's like well, technically, the fastest way is, you know, creating this one shot channel that watches. And once that gets something, it kicks off a receiving loop on a receiver, and then it does this lookup. If you can do that with a Vec. Find or whatever, just do it.

Speaker 1

就像,你知道的,除非你真的非常需要去榨取性能,否则在你能保持简单的地方尽量保持简单。你知道的,你会遇到像1Password这样的地方,那里会说,是的,我们必须做所有这些零化分配,而且不能记录动态字符串。在这个过程中,有一整套可记录的日志trait需要经过一系列处理才能正常工作。但这些并不是你每次都需要了解其内部机制的东西,对吧?

Like, you know, unless you really, really need to eke out that performance, keep things simple where you can. You know, you'll get to to places like 1Password where it's like, yeah, we have to do all this zeroizing allocation, and we can't log dynamic strings. There's a whole loggable trait in this whole process it has to go through to make it, you know, work. But that's not you know, you don't need to understand the internals of that every time. Right?

Speaker 1

你知道的,只要理解你必须掌握的部分,在你能保持简单的地方尽量保持简单。即使在这里,我们也会努力确保彼此负责,比如,事情不需要那么复杂。保持简单。没错。从技术上来说,另一种方式确实更快。

You know, just understand what you have to, keep things simple wherever you can. Even here, we, you know, we we try to make sure that we're holding each other accountable for, like, it doesn't need to be that hard. Keep it simple. Yes. It's technically faster this other way.

Speaker 1

但我们目前没有真实的数据集需要这种速度提升。你知道吗?当我们真的需要时,我们会去优化它。是的。将来我们可能会遇到这种情况,那时可能会出现性能瓶颈。

We don't have realistic data sets that need that speed up. You know? When we get there, we'll do that. Yes. In the future, we might have those, and we might see a slowdown.

Speaker 1

而当那一刻到来时,我们会去解决它,如此反复。所以我认为,很多时候归根结底就是Rust本身很复杂。在你能保持简单的地方,就尽量保持简单。遇到什么就学什么,但要一个一个来,循序渐进。

And guess what? When that happens, we'll fix it and so forth. So I think a lot of it just comes back to rust is complex. Keep it simple wherever you can. Learn everything that you come across, but, you know, take it one thing at a time.

Speaker 1

你最终一定会掌握的。这种模式一直适用于像1Password这样复杂的地方:在能保持简单的时候保持简单,而在无法简单的时候,就一次学一样东西。

You will eventually get there. And and that pattern is true all the way up into one password where things are complex is keep it simple where you can and then learn things one at a time when they can't be simple.

Speaker 0

我完全赞同这个观点。这很有道理,也和我所看到的情况一致。完全赞同,是的。

I can totally get behind that. It makes a lot of sense. It matches with what I see out there. Totally. Yeah.

Speaker 0

我们快接近尾声了。按照传统,最后一个问题就是:你对Rust社区有什么寄语?

We're getting close to the end. And, traditionally, the final question is, what's your statement to the Rust community?

Speaker 1

是的。我想,我认为其中一点就是,感谢Rust社区始终保持开放的态度,对吧?就像我说的,Rust有那么多书籍,Rust官方书籍,还有Brown版本的Rust书,里面配有测验和其他内容,非常棒,这些都很好。

Yeah. So, I mean, I think one of the you know, there there is some amount of, like, thank you to the Rust community for keeping things open. Right? Like I said, there are so many books out there in the Rust book, and the Brown version of the Rust book is is amazing with the quizzes and things. That's all great.

Speaker 1

我认为我们也需要继续甚至加强我们与他人交流的频率。对吧?站在对方的角度去理解他们知道什么、不知道什么。显然,像我这样背景的人刚进来时,社区里的人能这么做是非常关键的,对吧?

I think we also need to continue to or increase how often we relate to people. Right? Meet people where they're coming from, understanding, you know, what they do and don't know. And, obviously, with someone coming from my background, that was really critical that people here did that. You know?

Speaker 1

Rust社区中有很多缩写和计算机科学知识,而且有很多人非常聪明。有时候刚入门的时候,会听到他们说,“哦,你应该做一个beach reset”,你可能根本不知道这为什么重要,诸如此类的小问题还有很多,对吧?

And and there's a lot of, you know, acronyms or computer science knowledge, and there's so many people in Rust that are so smart. It can be difficult, you know, sometimes coming in and going, you know, they're like, well, you should make a beach reset. What I don't understand why that matters, you know, and so forth. And and just a lot of little things. Right?

Speaker 1

明白这一点很重要:你是如何学会你所学到的东西的?明白吗?这就像,哦,好吧,在我的操作系统课上,我们做过这个。但有时候会是,哦,我并没有做过。所以我觉得这方面还有很多可以改进的地方。我们需要找到一些学习路径,不仅仅是从零基础开始学Rust,我认为我们已经起步了,或者我们已经有了非常好的路径,比如通过《Rust编程语言》这本书;或者从Haskell转Rust,或者从C++转Rust,不管怎样。对吧?

Understanding how did you learn what you learned? You know? And it's like, oh, well, in my OS class, we did this. It's like, oh, I didn't So there's there's a lot of that that I think we can continue to improve on, just finding paths to not just go from zero to Rust, which I think we've started on or we have a really good path to with the Rust book, or to go from Haskell to Rust or c plus plus to Rust or whatever. Right?

Speaker 1

我觉得中间存在一个缺失的环节,比如如何从TypeScript转到Rust,或者其他类似的情况。这时候你会说,我懂变量,这些我都懂。所以《Rust编程语言》书的开头部分会让你觉得很无聊。明白吗?然后我就开始迷糊了。

I think there is a missing middle gap of how do you go from TypeScript to Rust or this or that where it's like, I understand variables. I understand all that. So the whole beginning of the Rust book feels boring. Know? I'm getting lost.

Speaker 1

然后我们直接跳到了内存管理,或者异步编程,以及异步到底是怎么工作的。有时候中间就缺少了这些衔接的部分。因此,我认为找到Rust的实际应用场景是非常关键的。在1Password公司和Rust学习小组中,我一直在推动的一件大事就是:我们怎样才能构建出一个完整统一的项目?这样就不是一个个地学习Rust的概念,也不是直接跳进1Password的代码库——那会让人感到害怕。

And then we go straight into memory or, you know, async and really how async works. And there are these missing pieces sometimes. And so I think finding practical applications of Rust is really critical. One of the big things I push for a lot within 1Password and the Rust study group is how can we build one cohesive thing? So it's not learning all the Rust concepts one by one, and it's not getting straight into the 1Password code base, which is terrifying.

Speaker 1

关键在于,我如何将这些概念应用到一个我亲手构建的项目中?现在我明白了,为什么Tokio的互斥锁和标准库的互斥锁是不同的,为什么它们的区别如此重要。在不同的场景下,你可能需要使用不同的锁。对吧?我看到它们在实际中的使用方式,现在我可以理解了,比如线程边界,或者更准确地说,是执行器(worker)之间的边界。

It is how do I learn these concepts and apply them to one thing that I have now built? And now I understand why, you know, a Tokyo Tokyo mutex and a standard mutex, they're different and why it matters that they're different. And you might need both in different cases. Right? I've seen it in use, and now I can understand, you know, thread boundaries or whatever it might be or or weight boundaries, I should say.

Speaker 1

于是这些概念开始对你有意义了,因为你有了真实的使用场景,而不是当初我学习它时的那种抽象概念。对吧?像rustlings这样的工具就非常棒,适合通过练习来学习。但到最后,我看不到练习六和练习十之间的联系,直到后来我才明白,它们可能是两个相关的知识点。所以你知道,很多人都会说,对,去构建东西。

And stuff starts to to make sense to you because you've had a real use case for it, not not just what it was when I learned it. Right? There's things like rustlings, which is incredible for, like, exercise based learning. But at the end, I didn't see exercise six mesh with exercise 10, and now I understand that those are two maybe related things. And so, you know, a lot of people say, right, build stuff.

Speaker 1

那是最好的学习方式,但并不是每个人都具备这样的现实条件。明白吗?在我成为开发者之前,我每周要工作五六十个小时,回家后还要保持公寓的整洁等等,根本没有那么多时间去专门构建东西。我当时花了一年甚至更多的时间才搞懂React,或者当时学的其他什么东西。如果当时我要学的是Rust,我根本不知道要花多久才能学会。明白吗?

That's that is the greatest way, but that's not not realistic for everyone. You know, I was working before I became a developer, I was working, you know, fifty, sixty hours a week and then, you know, coming home and trying to keep, you know, my apartment clean and all these things, and I did not have that much time left to just build things. It took me a year or more just to try and figure out, you know, React or whatever it was at the time. And if it were Rust I was trying to learn, I have no idea how long it would have taken. You know?

Speaker 1

所以我觉得,找到方法来弥补这些差距,构建出一种连贯的学习路径,让各个概念能够整体上变得有意义,这将是一个非常重要的领域,能够帮助很多人跨越Rust学习的鸿沟,从而推动Rust的广泛应用。明白吗?我在这里也看到过类似的情况,比如我们可能用Go语言来开发某个项目,因为要在我们的时间框架内让整个团队掌握Rust是不现实的。但如果存在更好的资源来帮助从Go过渡到Rust,这个问题就不存在了。明白吗?

And so I think just finding ways to bridge those gaps and and make cohesive learnings that make concepts actually make sense holistically. I think that's a really, really huge area that will help a lot of people close the gap of Rust, which will help Rust adoption. You know, I've seen that even here where it's like, we may have something we build in Go because ramping that team up on Rust is just not feasible in the time frame we have. Well, if there's better resources to get from Go to Rust, that becomes a nonissue. You know?

Speaker 1

我认为,当我们越愿意接纳那些处于中级水平的开发者进入Rust世界,Rust的发展就会越好。

And I think we'll see Rust grow the more we are open to bringing people in from more intermediate spaces into Rust.

Speaker 0

多么精彩而深刻的回答啊。我非常认同你的观点,也完全能感同身受。安德鲁,非常感谢你今天参加我们的播客节目。

What an amazing and insightful answer. I can really get behind it. I I can fully relate to that. Andrew, thanks so much for being on the podcast today.

Speaker 1

是的,非常感谢你们邀请我。这次交流让我感到非常愉快。

Yeah. Thank you very much for having me. I really, really enjoyed it.

Speaker 0

《Rust in Production》是由 Corout 制作的一档播客节目。由我 Matthias Endler 主持,Simon Bruggen 负责制作。如需节目笔记、文字稿以及了解我们如何帮助您的公司充分利用 Rust 的优势,请访问 corode.dev。感谢收听《Rust in Production》。

Rust in Production is a podcast by Corout. It is hosted by me, Matthias Endler, and produced by Simon Bruggen. For show notes, transcripts, and to learn more about how we can help your company make the most of Rust, visit corode.dev. Thanks for listening to Rust in Production.

关于 Bayt 播客

Bayt 提供中文+原文双语音频和字幕,帮助你打破语言障碍,轻松听懂全球优质播客。

继续浏览更多播客