Прошло 1,5 года, и наш энтузиазм угас. Он не сменился разочарованием — просто наступила тихая рутина. Сервис запущен в продакшен-среде, дэшборды зеленые, оповещения однообразные, и рабочий день кажется… нормальным. Именно в этот период суровая правда обычно дает о себе знать. Не в стартовых презентациях и не в процессе первого триумфального запуска, а спустя долгое время, когда проходит эффект новизны и система должна оправдывать свое существование в каждом спринте.

Эта статья посвящена именно такому периоду — тому, который наступает после «медового месяца», после выступлений на конференциях, после того, как ажиотаж в команде утихает и все возвращается в привычное русло. Здесь не будет ни уроков, ни предупреждений. Будет реальный отчет о создании CRUD-ориентированных бэкенд-систем, их запуске и, что важнее, необходимости жить с ними дальше.

Главный вывод прост: этот стек определенно может работать для CRUD-ориентированных бэкенд-систем — но только при условиях, которые многие команды недооценивают или игнорируют. Если эти условия не соблюдать, затраты не станут катастрофическими. Они просто будут незаметно расти.

Чего мы ожидали от Rust

Ожидания были разумными. Не наивными, не умозрительными.

Мы ожидали сокращения ошибок в продакшен-среде, особенно касающихся граничных случаев и обработки состояний. Мы ожидали, что рефакторинг будет безопаснее, потому что компилятор заставит нас пересмотреть неверные предположения вместо того, чтобы пропустить их в рантайм. Мы ожидали улучшения долгосрочной поддерживаемости по мере роста кодовой базы и смены ее авторов-создателей.

Никаких чрезмерных ожиданий. Мы исходили из опыта поддержки больших бэкенд-систем, где со временем накапливаются мелкие ошибки. Цель была не в скорости ради скорости — а в стабильности через дисциплину.

Мы недооценили не возможности инструмента, а то, что он потребует от нас взамен.

Как осуществлялись повседневные CRUD-операции 

Большая часть работы с CRUD (create, read, update, delete — создание, чтение, редактирование, удаление) на бэкенде не требует особых умственных усилий. Она повторяется, требует осторожности и постоянно меняется. 

Вы проверяете вводимые данные. Сопоставляете модели запросов со структурами домена. Преобразуете структуры домена в форматы постоянного хранения. Передаете ошибки наверх таким образом, чтобы сохранить их значение. На следующий день  делаете то же самое, но по немного другим правилам.

Эта схема никогда не менялась.

[Request]
   |
[Validate]
   |
[Map]
   |
[Persist]
   |
[Respond]

Что менялось постоянно — так это правила внутри этих блоков. Новые поля. Устаревшие флаги. Условная валидация. Частичные обновления. Функции только для администраторов. Переключатели функциональности, живущие дольше запланированного.

Ничего сверхъестественного. В этом и суть. CRUD — это скучно, а скучная работа усиливает проблемы.

Онбординг: первая скрытая стоимость

Мы предполагали, что новые бэкенд-разработчики войдут в курс дела примерно за 4-6 недель после онбординга. Так всегда было, когда мы работали на предыдущих стеках.

На практике освоение заняло около 3 месяцев.

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

Никто не отстал. Все научились. Но обучение шло довольно медленно, и это имело значение, учитывая рост команды и частую сменяемость ее членов.

Ожидаемое время освоения: ~1 месяц Фактическое время освоения: ~3 месяца.

Эта разница обходится дороже, чем планируют команды.

Время компиляции и обратная связь

Время компиляции не было катастрофичным. Оно было просто… постоянным.

Локальные инкрементальные сборки в среднем занимали 15–25 секунд после того, как выросла кодовая база. Чистые сборки — несколько минут. CI-пайплайны растянулись с примерно 10 минут на прежних стеках до 30–40 минут от начала до конца.

Ничто из этого не занимает целый день. Но все это растягивает цикл обратной связи  — медленно, но с нарастающим эффектом.

Edit -> Compile -> Test
   |------ longer ------|

Вы вносите сразу много изменений, вместо того чтобы выполнять их по одному. Вы дважды подумаете, прежде чем взяться за «мелкий» рефакторинг. Со временем это незаметно меняет ваше поведение — не кардинально, но ощутимо.

Продуктивность или надежность

Скорость разработки упала. Это суровая правда.

Скорость разработки новых функций в первые 6 месяцев была заметно ниже по сравнению с похожими сервисами, созданными нами ранее. Простые изменения требовали больше времени на реализацию. Вокруг границ корректности разрастался шаблонный код.

Но кое-что изменилось: откатов стало меньше. Срочные исправления в продакшен-среде стали редкостью. Код, который попал в основную ветку, оттуда уже не возвращался.

Надежность возросла, а скорость упала.

Этот компромисс реален, и не стоит закрывать на него глаза. Вопрос не в том, существует ли он, а в том, выигрывает ли ваша система от этого.

Где Rust явно не оправдал себя

Быстро меняющаяся бизнес-логика не подходила.

API для администрирования, внутренние инструменты и конечные точки, правила которых менялись еженедельно, требовали больших затрат на разработку при малой отдаче. Rust был неизменно строг, даже даже когда ошибки были незначительными и их было легко устранить.

Мы не заметили, как начали тратить время впустую. Разработчики тратили часы на проработку редких ошибок, которые в других языках можно было бы просто «перехватить» на лету. Система была корректна — но часто избыточно корректна.

Это не вина команды. Это просто неподходящий инструмент.

Где Rust неожиданно выручил больше всего

Долгосрочные рефакторинги проходили спокойнее.

Удаление полей, смена слоев хранения данных, ужесточение инвариантов спустя месяцы чувствовалось безопаснее. Границы владения данными стали явно прописаны в коде, а не хранились в головах разработчиков. Мертвый код было сложнее оставить.

Ничего драматичного. Не было ни одного яркого выигрышного момента. Просто со временем мы перестали спрашивать друг друга: «А точно ничего не нарушится, если это поменять?».

Ментальная плата за «корректность везде»

Самым сложным были не ошибки компилятора, а необходимость все продумывать заранее.

Каждое изменение требовало принятия заблаговременных решений: владение, времена жизни, границы ошибок, асинхронное поведение. Даже простые изменения требовали четкого понимания архитектуры с самого начала.

Simple Change
      |
[Design Decisions]
      |
[Implementation]

В стабильных проектах эти затраты оправданы. В постоянно меняющихся —  выматывают. И дело не в том, что инструмент плохой, а в том, что он не прощает неопределенности.

Сравнение с традиционными CRUD-стеками

В экосистеме Java/Spring рабочий процесс оптимизирован под скорость выражения. Вы сначала пишете намерение, а с последствиями разбираетесь позже — иногда слишком поздно.

Go казался быстрее для CRUD-систем с умеренными требованиями к корректности. Более простые ментальные модели позволяют выполнить более быструю итерацию ценой большей бдительности в рантайме.

Node и Python отлично подходят для быстро меняющихся доменов, где возможность быстро изменить поведение перевешивает риск трудноуловимых ошибок.

Разница — не в возможностях языка. А в том, как быстро идеи превращаются в работающий код.

Переломный момент через 1,5 года 

Где-то к концу первого года все стабилизировалось. Время компиляции перестало расти. Паттерны устоялись. Вводить новых людей в курс дела стало не так болезненно — в команде остались только те, кому было комфортно работать в этих рамках.

Через 1,5 года затраты стали предсказуемыми, а польза — ощутимой. Мы не пожалели, что выбрали Rust, но и эйфории не было.

Вот так выглядит зрелость.

Когда Rust окупается для CRUD

Использование Rust для CRUD-ориентированных бэкенд-систем оправдывает себя при следующих условиях:

  • Бизнес-логика и правила редко меняются.
  • Стоимость ошибок в работе системы действительно высока.
  • Сервис рассчитан на годы.
  • CRUD это часть инфраструктуры, а не площадка для экспериментов с продуктом

Только в таких случаях игра стоит свеч.

Когда Rust не окупается для CRUD

Rust вредит больше, чем помогает, когда:

  • Бизнес-правила меняются еженедельно.
  • Преобладают API для администрирования и внутренние инструменты.
  • Скорость итераций важнее долгосрочной надежности.
  • Команды оптимизированы на скорость разработки, а не на долголетие.

Игнорировать это — значит тратить энергию команды впустую, не получая выгоды.

Суровая правда

Rust нас не подвел. Наши ожидания просто не соответствовали характеру работы.

Low Churn + High Risk  -> Rust Works
High Churn + Low Risk -> Rust Hurts

Опытный инженер отличается не умением выбирать самые мощные инструменты, а пониманием, когда их мощь перестает помогать и начинает мешать.


Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи The Cache Cowgirl: Is Rust Worth It for Backend CRUD? The Harsh Truth After 18 Months

Предыдущая статьяМои любимые фронтенд-инструменты, о которых никто не говорит