Вы тоже хоть раз ловили себя на мысли: «А может, ну его, этот Node.js — перепишем всё на Rust, и будет летать?»
Поздравляю — вы не одиноки. Я тоже через это прошёл.
В этой статье я разложу по полочкам, когда действительно стоит лезть в Rust, а когда лучше остаться на TypeScript и просто выспаться. Без фанатизма, маркетинга и с примерами из практики.
Зачем вообще думать о переписывании
Переписывать код ради хайпа — худшее, что можно сделать с живым продуктом. Но иногда ситуация доходит до того, что без хирургии никак:
Латентность скачет как курс крипты. p99 вылезает за все рамки, а пользователи жалуются на тормоза.
CPU кипит, как чайник. Оптимизировали всё, что можно, а сервис всё равно жрёт ресурсы.
GC устраивает вечеринку на проде. Временами всё просто замирает.
Безопасность. Сервисы, работающие с низкоуровневыми данными (шифрование, парсинг, форматы).
Если ничего из этого нет — расслабьтесь. TypeScript вам подходит идеально.
Что хорошего в TypeScript
TypeScript — это комфорт, гибкость и скорость.
Куча библиотек, отличная экосистема, быстрая разработка, всё ясно и прозрачно.
Он идеален, когда:
сервис I/O-bound (много запросов, мало вычислений);
важна скорость изменения бизнес-логики;
команда большая и разноуровневая.
Вывод: если узкое место не в CPU — оставайтесь на TS. Там, где важнее бизнес, чем наносекунды, Rust просто не окупится.
Зачем вообще Rust?
Rust — как спорткар: быстрее, надёжнее, безопаснее, но требовательный к водителю.
Что он реально даёт:
Скорость. Никакого GC, минимум абстракций, всё чётко.
Память. Контроль, предсказуемость, никаких утечек.
Параллелизм. Tokio и async дают гибкость без боли.
Безопасность. Borrow checker — не враг, а телохранитель.
Но давайте честно: разработка в Rust медленнее, найм дороже, а ментальное усилие — выше. Это не язык «для всех».
Где выигрыши настоящие, а не иллюзорные
Сценарий |
Что даёт Rust |
Реальный прирост |
---|---|---|
CPU-bound вычисления |
Нет интерпретации JS |
x2–x10 |
Работа с памятью / GC |
Предсказуемость |
-50–70% латентности на p99 |
Безопасность (crypto, parser) |
Нет UB / утечек |
? priceless |
I/O-bound API |
Почти без разницы |
±0% |
Не путайте «производительность» с «ощущением контроля». Иногда просто измерения дают больший прирост, чем Rust.
Как подойти без боли (и увольнений)
Полный «big rewrite» — это билет в ад. Рабочие проекты так не делают.
Вот проверенные пути:
? 1. Вынести горячий кусок
Нашли bottleneck — вынесите в отдельный микросервис на Rust.
gRPC, HTTP, хоть сокеты — не важно. Так безопаснее всего.
? 2. N-API / napi-rs / Neon
Маленький CPU-модуль можно собрать в native addon.
Node.js остаётся обвязкой, Rust делает тяжёлую работу.
#[napi]
fn sum(a: i32, b: i32) -> i32 {
a + b
}
И вызывать это из TypeScript как обычную функцию. Красота.
? 3. WebAssembly
Отличный вариант, если у вас edge-сервисы, Cloudflare Workers, или нужен общий код между backend и frontend.
? 4. Полная переписка
Только если код уже нельзя поддерживать, и переписка дешевле латания.
(спойлер: это редкость).
Пример для наглядности
Вот тот самый «учебный» пример с Fibonacci.
TypeScript:
function fib(n: number): number {
return n < 2 ? n : fib(n - 1) + fib(n - 2);
}
Rust:
fn fib(n: u32) -> u64 {
match n {
0 => 0, 1 => 1, n => fib(n - 1) + fib(n - 2)
}
}
На небольших n
— одинаково. На больших — Rust уходит вперёд, как болид на прямой. Но кто в продакшене вообще считает Fibonacci без кеша?..
Как понять, что Rust действительно помог
Без метрик — всё гадание на кофейной гуще.
Проверяйте:
p50 / p95 / p99 latency
CPU load
память
RPS на инстанс
стоимость облака
Смотрите не только на скорость, но и на стабильность хвостов. Rust часто даёт не столько прирост, сколько предсказуемость.
Чеклист: стоит ли вам вообще туда лезть
Отметьте галочками:
☐ У вас CPU-bound сервис
☐ Проблемы с GC или памятью
☐ p99 тормозит и влияет на бизнес
☐ Есть в команде Rust-разработчики (или желание стать ими)
☐ Хотите снизить расходы на инфраструктуру
Если набралось 3+ — сделайте прототип в Rust.
Если нет — закройте вкладку и займитесь профилированием на Node.
И немного философии напоследок
Rust — не серебряная пуля. Это инструмент, который даёт мощь и контроль, но требует зрелости и дисциплины.
TypeScript — это про скорость и бизнес. Rust — про контроль и эффективность.
Главное — не язык. Главное — понимание, где узкое место, и зачем вы его меняете.
Измеряйте, прототипируйте, проверяйте гипотезы.
Тогда ваша команда будет не просто писать код, а принимать инженерные решения.
? Итог: не переписывайте всё — перепишите только то, что действительно тормозит.
Rust — как хороший нож: в умелых руках он режет отлично, в неумелых — просто оставляет шрамы.
Комментарии (14)
kotan-11
09.10.2025 08:39В Rust нет compile-time гарантий целостности для структур, размещённых в хипе. Вместо этого он использует флаги, счетчики и проверки во время выполнения, которые вызывают panic и аварийно завершают программу.
Управление объектами в хипе основано на умных указателях с подсчётом ссылок, как в C++, что приводит к утечкам памяти.
Rust не предотвращает дедлоки.
Все приложения на Rust прямо или косвенно импользуют
unsafe
, теряя безопасность памяти и защиту от data races.Паники часто возникают при работе с optional, заимствованиями и приведениями типов, если их специально не обрабатывать. В этом выражении приведения типов три возможных краша (кстати, как вам такой синтаксис простого приведения типов?):
result.unwrap().borrow().as_any().downcast_ref::<RefCell<T>>().expect("!").clone()
-
Синтаксис адски переусложнен даже для простых операций. Вот пример безопасного присваивания полю структуры по maybe-null-указателю:
ptr.and_then(|x| x.try_borrow_mut().ok()).map(|mut x| x.field = 1);
Вот пример того же кода на языке Аргентум:
ptr?_.field := 1
- просто, предсказуемо и безопасно. И хотя Аргентум решает все перечисленные выше проблемы, работая без паник, утечек, unsafe, гонок, дедлоков и GC, я его пока не рекомендую из-за его экспериментального статуса.
andreymal
09.10.2025 08:39гарантий целостности для структур, размещённых в хипе
О чём конкретно речь?
Управление объектами в хипе основано на умных указателях с подсчётом ссылок
Ложь, контейнеры вроде
Box<T>
иVec<T>
не имеют подсчёта ссылокВсе приложения на Rust прямо или косвенно импользуют
unsafe
, теряя безопасность памяти и защиту от data races.Вы не поняли суть Rust
Паники часто возникают
Ложь, в приведённом вами выражении вы сами целенаправленно вызываете панику, они не возникают сами по себе
(кстати, как вам такой синтаксис простого приведения типов?)
Никак, потому что вы не дали никакой информации о том, что такое
result
и зачем вы всю эту чушь вообще написалиmaybe-null-указателю
У указателей не существует метода
and_then
, так что где-то тут вы опять лжётеВот пример того же кода на языке Аргентум
А, так это просто бездарная реклама от человека, который даже не потрудился изучить основы Rust, чего я тут распинаюсь вообще... Просто держите минус тогда
andreymal
09.10.2025 08:39Ну и раз уж речь зашла про Аргентум:
работая без ... unsafe
Загоревшись интересом, как такие чудеса в принципе возможны, я заглянул в исходники на гитхабе, а там стандартная библиотека написана на C — то есть она вся автоматически unsafe
За конкретным примером даже далеко ходить не пришлось, можно взять сразу хелловорлд — стандартная функция
log
не стесняясь напрямую вызывает fputs, вызов которой конечно же является unsafe: вызывающий её программист обязан самостоятельно проконтролировать, что строкаs->chars
является null-terminated и что её чтение не приведёт к чтению за пределами выделенной памятиИ если один пункт рекламы оказался ложным — возможно, и в других пунктах стоит засомневаться?
kotan-11
09.10.2025 08:39работая без ... unsafe
В языке Argentum нет unsafe mode, в отличие от Rust.
вызывающий её программист обязан самостоятельно проконтролировать, что строка
s->chars
является null-terminated и что её чтение не приведёт к чтению за пределами выделенной памятиВы совершенно правы. Строка,
s->chars
является null-terminated, это гарантируется самим языком. Никакие операции над строками не могут создать последовательность utf-8 символов без 0-терминатора. Если идти дальше, s никогда не может быть null, это гарантируется системой типов Аргентума и никогда не может показывать на мусор. Поэтому выражение fputs(s->chars, stdout); безопасно.Но конечно, FFI это всегда дыра в безопасности (escape hatch, как любят писать в научных статьях). С этим ничего сделать к сожалению нельзя, можно только сократить периметр общения с внешним миром до рантайм-библиотеки. Это, кстати, справедливо и для всех managed-языков, таких как JS/Java/Python и т.д.
andreymal
09.10.2025 08:39Строка,
s->chars
является null-terminated, это гарантируется самим языком.И снова ложь. Открываем объявление структуры AgString:
char chars[1]; // variable size zero terminated utf8
Здесь не только нет никаких гарантий безопасности (нет, комментарий «zero terminated» не является такой гарантией), но и вообще большие подозрения на неопределённое поведение. Вы проводите странные манипуляции со структурой, выделяя больше памяти чем размер структуры и обращаясь за пределы структуры, чтобы записать целую строку в массив размером один элемент — жутко страшный код.
Кроме того, вы вручную подсчитываете количество выделяемой памяти и столь же вручную пишете нулевой байт в
s->chars[size]
— ничего из этого язык C не проверяет, все эти операции являются unsafe и работают только благодаря вашей собственной аккуратности, а не каким-то там гарантиям.Почти каждая строчка в
runtime.c
— это потенциальный выстрел в ногу, о каких вообще гарантиях может идти речь?kotan-11
09.10.2025 08:39Последнее поле char[1] и malloc(sizeof(MyStruct)+extra_data)- это классический подход для представления структур переменного размера, который работает во всех версиях C (в С99) его расширили до char[]. Вы не обязаны этого знать, это низкоуровненое программирвование.
Конечно, рантайм любого целевого языка как правило пишется на языке более низкого уровня, менее безопасном, и это само по себе не делает целевой язык менее safe. Например Python VM реализована на С со страшной адресной арифметикой и "небезопасными" операциями. И при этом Python - managed и memory safe язык.
Все гарантии безопасности языка распространяются на программы написанные на этом языке. При этом внутренняя реализация его рантайма не играет никакой роли. То же самое применимо и к Аргентуму, его безопасность заключается в том, что любая успешно скомпилированная программа на этом языке может упасть только при исчерпании системных ресурсов или при вызове системной функции terminate.
andreymal
09.10.2025 08:39рантайм любого целевого языка как правило пишется на языке более низкого уровня, менее безопасном
Всё верно: unsafe Rust — язык более низкого уровня, менее безопасный чем safe Rust
Все гарантии безопасности языка распространяются на программы написанные на этом языке
Всё верно: гарантии безопасности safe Rust распространяются только на safe Rust, при этом внутренняя реализация рантайма на unsafe Rust не играет никакой роли
любая успешно скомпилированная программа на этом языке может упасть только при
...любой случайной вашей опечатке в unsafe-коде
runtime.c
и это само по себе не делает целевой язык менее safe
То есть вы признаёте свою неправоту и отказываетесь от пункта 4 своего изначального комментария
kotan-11
09.10.2025 08:39> гарантий целостности для структур, размещённых в хипе
О чём конкретно речь?
Раст рекламируется как язык, следящий за владением, и не позволяющий одновременных мутабельных алиасов. Но эти гарантии провеяются на этапе компиляции только для стековых объектов и заимствований. В то время как в хипе вызовы borrow/borrow_mut не проверяются на стадии компиляции, а вместо этого используя счетчики внутри RefCell убивают ваше приложение в рантайме.
> Управление объектами в хипе основано на умных указателях с подсчётом ссылок
Ложь, контейнеры вроде
Box<T>
иVec<T>
не имеют подсчёта ссылокКонтейнеры вроде
Box<T>
не позволяют создавать иерархии (графы) объектов, поскольку на объект в таком контейнере нельзя иметь ссылку из другого объекта. Поэтому Box<T> это про полиморфизм и рекуривные (безразмерные) типы а не про иерархические структуры данных в хипе.> Все приложения на Rust прямо или косвенно импользуют
unsafe
, теряя безопасность памяти и защиту от data races.Вы не поняли суть Rust
Похоже да, я не понял суть Раста. Он рекламируется как safe, но его ограничения приводят к тому, что 20-30% всех приложений на Расте непосредственно используют unsafe блоки кода, а 50-80% приложений имеют зависимости первого уровня от unsafe crates. Получается, что язык не совсем safe?
> Паники часто возникают
Ложь, в приведённом вами выражении вы сами целенаправленно вызываете панику, они не возникают сами по себе
Если простое выражение на языке успешно компилируется, а при исполнении с некоторой пероятностью падает - это не нормально. Вы не находите?
> (кстати, как вам такой синтаксис простого приведения типов?)
Никак, потому что вы не дали никакой информации о том, что такое
result
и зачем вы всю эту чушь вообще написалиВам надо что-то делать со своим гневом.
Давайте по-другому, допустим у нас есть nullable-ссылка на полиморфный объект, например result: Option<Rc<RefCell<dyn Any>>> // простой синтаксис, правда.
Как получить из нее Option<Rc<RefCell<MyType>>>?> maybe-null-указателю
У указателей не существует метода
and_then
, так что где-то тут вы опять лжётеКлассическая Maybe-monad в Расте == Option. Поэтому maybe-null-указатель - как раз имеет
Option::and_then
Вам определенно нужно или исключить из лексикона слово "лжете" или окончательно перейти на стиль "врешь собака".
> Вот пример того же кода на языке Аргентум
А, так это просто бездарная реклама от человека, который даже не потрудился изучить основы Rust, чего я тут распинаюсь вообще... Просто держите минус тогда
Я не рекламирую Аргентум, он пока не готов к промышленной .эксплуатации. Я лишь указываю на некоторые технические несоответствия между обещаниями Раста и его реальным состянием.
Но знаете, самое неприятное в Расте даже не то, что он течет и падает, не его вырвиглазный синтаксис, а его комьюнити, в котром оскорбления считаются нормой.
andreymal
09.10.2025 08:39убивают ваше приложение в рантайме
И снова ложь. Во-первых, паники не убивают приложение, их можно перехватить и обработать (хотя скорее всего не нужно). Во-вторых, здесь добавляется ваша ложь из пункта 5: вас никто не заставляет вызывать заведомо паникующие методы, вы вполне можете использовать try_borrow/try_borrow_mut
не позволяют создавать иерархии (графы) объектов
Обратите внимание, что это совершенно не то, что вы изначально написали в пункте 2, то есть вы сейчас подменили тезис
Получается, что язык не совсем safe?
Никакой язык не может быть полностью safe даже в теории. Аргентум тоже оказался unsafe, и, что гораздо хуже — Аргентум, будучи написанным на C/C++, не контролирует своё собственное использование unsafe. Rust лучше уже хотя бы в том плане, что он пытается изолировать unsafe-код в unsafe-блоках
Если простое выражение на языке успешно компилируется, а при исполнении с некоторой пероятностью падает - это не нормально. Вы не находите?
Если вы целенаправленно используете функции, в документации которых написано, что они предназначены для того чтобы падать, то падение это абсолютно нормально и является не проблемой, а ожидаемым поведением программы. Придумайте более адекватный пример (я знаю, что его можно придумать, но раз именно вы тут любите хейтить Rust, то вы и придумайте, я не буду)
Option<Rc<RefCell<dyn Any>>>
Давайте с самого начала — зачем такое значение в принципе существует? С некоторой вероятностью это может оказаться криворукостью написавшего это программиста — а рассматривать заведомый говнокод я не вижу смысла (говнокод можно написать на любом языке)
Классическая Maybe-monad в Расте == Option
А здесь подмена понятий с вашей стороны, потому что Option не является указателем и даже не обязан хранить в себе указатель
Домашнее задание для читателей — посчитать, сколько правил демагога использовал kotan-11 в своих комментариях
kotan-11
09.10.2025 08:39Придумайте более адекватный пример
Я завтра напишу адекватную задачу - бенчмарк языков программирования с точки зрения поддержки высокоуровневых структур данных которые составляют основу современных приложений. Я покажу реализацию этого бенчмарка на С++, JS и Аргентуме, а вы - на любых языках, которые считаете подходящими.
severgun
09.10.2025 08:39В этой статье я разложу по полочкам, когда действительно стоит лезть в Rust, а когда лучше остаться на TypeScript и просто выспаться. Без фанатизма, маркетинга и с примерами из практики
Уже второй или третий ИИ-слоп от этого автора с этим интро.
Стоит ли говорить что ни в одной статье не было практики ни от автора, ни от ИИ.
Стоит забанить аккаунт за спам.
sergey_prokofiev
Но как же наносекунды с сетевыми то вызовами, карл?? :)