重写之前,我们濒临崩溃 我们是一个六人团队。作为后端工程师,我们疲于奔命地应付着微服务、流水线、运维补丁以及读起来像心理治疗笔记的事故报告。
我们的技术栈对于一个快速发展的初创公司来说很典型:
我们并非能力不足,只是不够快。服务功能是有的,但很脆弱。
有些早晨,我们会一起盯着 Datadog 仪表盘,看着队列积压的消息数超过一万条,等待垃圾回收赶上进度。
我们每天都在“救火”。
然后,我们中最沉默寡言的 Kabir 说:
“我觉得我可以用 Rust 重写这个图像处理流水线。”
接下来发生的事情本应显而易见 我们都耸耸肩。重构项目从来都活不下来。
但 Kabir 没有寻求帮助。他没有预订设计会议,也没有要求估算时间。他只是默默地开始了。
在我们给 API 的分页功能打补丁时,他正在用 image-rs 库对比测试我们的 Node 脚本。
我们甚至没有注意到——直到他做了演示。
让我们过时的数据 Kabir 在下一次迭代评审会上演示了新的 Rust 服务。我们笑了。我们鼓掌了。
我们当时没有意识到,我们是在为自己被取代而鼓掌。
他展示的数据如下:
| 指标 | Node.js (重构前) | Rust (重构后) | | :------------------ | :--------------- | :------------ | | P95 延迟 | 243ms | 39ms | | Lambda 冷启动时间 | 1.8s | 240ms | | 内存使用量 | 300MB | 32MB | | 每日错误数 | ~500 | <10 | | 基础设施月成本 | ~$1200 | $110 |
Kabir 不仅仅是提升了性能。 他降低了 AWS 账单。 他消除了那些不稳定的依赖项。 他让值班轮换变得几乎无聊。
我们当时没说,但我们都感觉到了: 这不仅是一个更好的服务,更体现了一个更优秀的工程师。
我们其他人迅速落后了 Kabir 成了负责性能的人。
当我们还在修复损坏的 Mongoose 模式、争论 GraphQL 和 REST 时,他已经在撰写关于零成本抽象(zero-cost abstractions)以及 epoll 与 kqueue 的 RFC(征求意见稿)了。
他并不傲慢。但他也没有等我们。
我们开始问这样的问题:
Pin<Box<T>>
到底是什么来着?”差距迅速扩大。
前一周,他还在用 Axum 框架构建我们的健康检查。 下一周,他已经用原子计数器(atomic counters)和 parking_lot 库做出了一个生产就绪的速率限制器。
我们停止评审他的 PR(Pull Request)了。我们跟不上了。
组织悄然转变,然后剧烈变动 Kabir 不仅仅是在构建更快的服务。他正在改变所有权的归属。
产品经理(PM)开始把功能请求直接分配给他。 站点可靠性工程师(SRE)请他协助修改 Terraform 配置。 领导层开始在全员会议(all-hands)上展示他的仪表盘。 他成了“那个后端专家”——即使我们还有五个人在岗。
那天我们并没有失业。
但我们不再是那个团队了。
然后裁员来了 他们没有称之为裁员。他们从来不会这么说。
他们说公司要“重新聚焦”。说是在“优化交付层”。
我们一个接一个地收到了来自人力资源部(HR)的日历邀请。
没有绩效改进计划(PIP)。没有警告。只有“感谢您这段时间的付出”。
他们留下了 Kabir。
他们当然会留下他。
他现在负责了一半的基础设施。而且做得比我们整个团队过去做的还要好。
重构并非邪恶——它是合乎逻辑的 需要澄清的是:Kabir 并没有陷害我们。他没有游说反对任何人。他也没有要求组织缩减规模。
他只是让自己变得不可或缺,无法被裁掉。
在一家衡量每次部署投资回报率(ROI)的初创公司里,你不会裁掉那个能以 10 倍速度交付、成本却只有 1/5 的人。
我们被解雇不是因为我们差劲。 我们被解雇是因为他让我们看起来可有可无。
以下是一段取代了我们的代码示例
use axum::{Router, routing::get, Json};
use serde::Serialize;
use std::{sync::Arc, time::SystemTime};
#[derive(Serialize)]
struct Health {
status: &'static str,
uptime_seconds: u64,
}
async fn health_check(start_time: Arc<SystemTime>) -> Json<Health> {
let uptime = SystemTime::now()
.duration_since(*start_time)
.unwrap_or_default()
.as_secs();
Json(Health {
status: "ok",
uptime_seconds: uptime,
})
}
#[tokio::main]
async fn main() {
let start_time = Arc::new(SystemTime::now());
let app = Router::new().route(
"/health",
get({
let start_time = start_time.clone();
move || health_check(start_time.clone())
}),
);
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
是的,它很简洁。是的,它很快。
但这不是一个 Node.js 工程师可以轻松上手的。
学习曲线是陡峭的(vertical),而公司里没有其他人爬了上去。
我们的反思报告 回顾过去,问题出在这里——而且没有一条是关于 Rust 本身的:
最后一点思考 解雇我们的不是 Rust。
但一场没有团队共识的 Rust 重构,却可以改变团队本身的构成。
如果一个人在重构一切,而其他人还在写 Jira 工单,那么他们不仅仅是在提升吞吐量——他们是在重构组织结构图。
如果你正目睹这一切发生?
不要只是旁观。
去学习。去结对。去贡献。否则,你就有可能成为历史。