Вы тоже хоть раз ловили себя на мысли: «А может, ну его, этот 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)


  1. sergey_prokofiev
    09.10.2025 08:39

    Там, где важнее бизнес, чем наносекунды, Rust просто не окупится.

    Нашли bottleneck — вынесите в отдельный микросервис на Rust.
    gRPC, HTTP, хоть сокеты — не важно. Так безопаснее всего.

    Но как же наносекунды с сетевыми то вызовами, карл?? :)


  1. kotan-11
    09.10.2025 08:39

    1. В Rust нет compile-time гарантий целостности для структур, размещённых в хипе. Вместо этого он использует флаги, счетчики и проверки во время выполнения, которые вызывают panic и аварийно завершают программу.

    2. Управление объектами в хипе основано на умных указателях с подсчётом ссылок, как в C++, что приводит к утечкам памяти.

    3. Rust не предотвращает дедлоки.

    4. Все приложения на Rust прямо или косвенно импользуют unsafe, теряя безопасность памяти и защиту от data races.

    5. Паники часто возникают при работе с optional, заимствованиями и приведениями типов, если их специально не обрабатывать. В этом выражении приведения типов три возможных краша (кстати, как вам такой синтаксис простого приведения типов?):
      result.unwrap().borrow().as_any().downcast_ref::<RefCell<T>>().expect("!").clone()

    6. Синтаксис адски переусложнен даже для простых операций. Вот пример безопасного присваивания полю структуры по maybe-null-указателю:
      ptr.and_then(|x| x.try_borrow_mut().ok()).map(|mut x| x.field = 1);

      Вот пример того же кода на языке Аргентум: ptr?_.field := 1 - просто, предсказуемо и безопасно. И хотя Аргентум решает все перечисленные выше проблемы, работая без паник, утечек, unsafe, гонок, дедлоков и GC, я его пока не рекомендую из-за его экспериментального статуса.


    1. andreymal
      09.10.2025 08:39

      гарантий целостности для структур, размещённых в хипе

      О чём конкретно речь?

      Управление объектами в хипе основано на умных указателях с подсчётом ссылок

      Ложь, контейнеры вроде Box<T> и Vec<T> не имеют подсчёта ссылок

      Все приложения на Rust прямо или косвенно импользуют unsafe, теряя безопасность памяти и защиту от data races.

      Вы не поняли суть Rust

      Паники часто возникают

      Ложь, в приведённом вами выражении вы сами целенаправленно вызываете панику, они не возникают сами по себе

      (кстати, как вам такой синтаксис простого приведения типов?)

      Никак, потому что вы не дали никакой информации о том, что такое result и зачем вы всю эту чушь вообще написали

      maybe-null-указателю

      У указателей не существует метода and_then, так что где-то тут вы опять лжёте

      Вот пример того же кода на языке Аргентум

      А, так это просто бездарная реклама от человека, который даже не потрудился изучить основы Rust, чего я тут распинаюсь вообще... Просто держите минус тогда


      1. andreymal
        09.10.2025 08:39

        Ну и раз уж речь зашла про Аргентум:

        работая без ... unsafe

        Загоревшись интересом, как такие чудеса в принципе возможны, я заглянул в исходники на гитхабе, а там стандартная библиотека написана на C — то есть она вся автоматически unsafe

        За конкретным примером даже далеко ходить не пришлось, можно взять сразу хелловорлд — стандартная функция log не стесняясь напрямую вызывает fputs, вызов которой конечно же является unsafe: вызывающий её программист обязан самостоятельно проконтролировать, что строка s->chars является null-terminated и что её чтение не приведёт к чтению за пределами выделенной памяти

        И если один пункт рекламы оказался ложным — возможно, и в других пунктах стоит засомневаться?


        1. 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 и т.д.


          1. 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 — это потенциальный выстрел в ногу, о каких вообще гарантиях может идти речь?


            1. 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.


              1. andreymal
                09.10.2025 08:39

                рантайм любого целевого языка как правило пишется на языке более низкого уровня, менее безопасном

                Всё верно: unsafe Rust — язык более низкого уровня, менее безопасный чем safe Rust

                Все гарантии безопасности языка распространяются на программы написанные на этом языке

                Всё верно: гарантии безопасности safe Rust распространяются только на safe Rust, при этом внутренняя реализация рантайма на unsafe Rust не играет никакой роли

                любая успешно скомпилированная программа на этом языке может упасть только при

                ...любой случайной вашей опечатке в unsafe-коде runtime.c

                и это само по себе не делает целевой язык менее safe

                То есть вы признаёте свою неправоту и отказываетесь от пункта 4 своего изначального комментария


      1. 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, чего я тут распинаюсь вообще... Просто держите минус тогда

        Я не рекламирую Аргентум, он пока не готов к промышленной .эксплуатации. Я лишь указываю на некоторые технические несоответствия между обещаниями Раста и его реальным состянием.

        Но знаете, самое неприятное в Расте даже не то, что он течет и падает, не его вырвиглазный синтаксис, а его комьюнити, в котром оскорбления считаются нормой.


        1. 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 в своих комментариях


          1. kotan-11
            09.10.2025 08:39

            Придумайте более адекватный пример

            Я завтра напишу адекватную задачу - бенчмарк языков программирования с точки зрения поддержки высокоуровневых структур данных которые составляют основу современных приложений. Я покажу реализацию этого бенчмарка на С++, JS и Аргентуме, а вы - на любых языках, которые считаете подходящими.


  1. severgun
    09.10.2025 08:39

    В этой статье я разложу по полочкам, когда действительно стоит лезть в Rust, а когда лучше остаться на TypeScript и просто выспаться. Без фанатизма, маркетинга и с примерами из практики

    Уже второй или третий ИИ-слоп от этого автора с этим интро.

    Стоит ли говорить что ни в одной статье не было практики ни от автора, ни от ИИ.

    Стоит забанить аккаунт за спам.


  1. AirLight
    09.10.2025 08:39

    Почему сразу хардкорный Rust? Есть же производительные языкы с меньшим порогом входа - C#, Java, Go.


    1. andreymal
      09.10.2025 08:39

      В них всех тоже есть GC, так что шило на мыло. Бывали истории о переходе с Go на Rust из-за тормозов