Статическая типизация и эффективная разработка на Rails

 Публичный пост для комнаты «Тех»
12 сентября 2025  629

Привет. Небольшой дисклаймер: Пост выкладываю больше на поговорить, чем чем-то поделиться. Я был удивлен, какая это неоднозначная тема в руби комьюнити. Вот интересно узнать мнение русского среза.

Ruby давно славится своей гибкостью и удобным синтаксисом, позволяющим быстро создавать прототипы да и не только их. Однако эта свобода имеет свою цену: по мере роста проектов поддержка и отладка становятся всё более затратными.

Многие разработчики считают статическую типизацию ненужным препятствием, замедляющим работу. Но, как и автоматические тесты, статическая типизация (с помощью RBS или Sorbet) — это инвестиция, которая окупается с лихвой. Она не только ускоряет разработку после первоначального освоения, но и служит бесплатной документацией, облегчая поддержку кода и снижая общие издержки.

Баланс: первоначальные усилия против долгосрочной эффективности

Внедрение статической типизации в Ruby действительно требует начальных усилий. Нужно изучить RBS или Sorbet, а также аннотировать существующий код. Однако эта инвестиция поможет уже в скором времени:

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

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

  • позволит проводить более безопасный рефакторинг.

Если ваша команда тратит часы на поиск ошибок, вызванных неожиданными аргументами методов или значениями nil, статическая типизация значительно сократит это время.

Сигнатуры типов как бесплатная документация

Как часто вы открывали код на Ruby и не могли понять, какие параметры ожидает метод и что он возвращает? В динамически типизированных языках приходится догадываться, читать тесты или искать документацию (если она есть), ну или курить код.

Со статической типизацией код сам предоставляет эти ответы. Вместо расплывчатых комментариев вроде:

# Обрабатывает заказ и возвращает подтверждение
# @param order [Order] - заказ для обработки
# @return [String] - сообщение подтверждения
def process_order(order)
  # логика метода
end

можно определить это с помощью RBS или Sorbet, обеспечивая актуальность и точность информации:

sig { params(order: Order).returns(String) } # Пример для Sorbet, но можно использовать и rbs-inline
def process_order(order)
  # логика метода
end

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

Предотвращение ошибок до их возникновения

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

Рассмотрим распространённую ошибку:

def add_numbers(a, b)
  a + b
end

add_numbers("10", 5) # Ошибка во время выполнения!

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

С помощью проверки типов эта проблема была бы обнаружена сразу:

# @rbs (Integer,  Integer) -> Integer
def add_numbers(a, b)
  a + b
end

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

Безопасный и предсказуемый рефакторинг

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

Со статической типизацией ваш редактор и проверяльщик типов сразу укажут на все места, где требуется изменение. Больше не нужно надеяться, что тесты поймают всё — статическая типизация делает рефакторинг предсказуемым и спокойным процессом.

Если вы всерьёз настроены создавать поддерживаемые приложения на Rails, которые масштабируются без головной боли, статическая типизация — мощный инструмент, который не стоит игнорировать.


ЗЫ: Статическая типизация, как и тесты, да как и стиль кода - это выбор каждого. Можно взять и использовать от и до, можно лишь взять то, что нужно для конкретного проекта. Статическая типизация отлично работает как с новыми так и уже со старыми проектами. Необязательно покрывать весь код типами данных. Вы сами решаете что да как.

Буду рад любому обсуждению в комментариях. За / Против / А поговорить - любоей подойдет.


Если просто хочется быть в теме, то я веду ежемесячную рассылку по статической типизации в Ruby: link.

Связанные посты
22 комментария 👇

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

Зачастую проблема возникает в том, что другое АПИ ответило "10" вместо 10. Тогда вообще чистый Яваскрипт всем в помощь, потому что в нём всем этим каком управлять намного проще.

А типопроверки и дебаг можно оставить на ЛЛМках. Они это просечь могут задолго до того, что надо будет вводить типизацию.

ПЫСЫ.

Странно, пост со скидкой для вастрикан, но при этом - публичный. А если прочитать статью, то она сама по себе состоит из 13 абзацев и просто пиарит твои курсы. Самого по себе содержания в этой статье - кот наплакал. "Берите статическую типизацию, она вам нужна, спасибо".

Как-то не по правилам контента, и ничего полезного в клуб не вносит. @moderator

  Развернуть 1 комментарий

@newarked, +1, кроме, по сути, самопиара курса, тут ничего особо и нет. Хоть и приятно читать Ruby-related штуки, но всё же давайте не превращать клуб в очередную помойку как linkedin..

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

  Развернуть 1 комментарий

И ах да, я всецело за образовательные инициативы, против самого курса я, конечно, ничего не имею, но более подходящее место, если уж в самой статье нет какого-то исключительного смака (и пользы для клубчан), было бы самопиар-темы пет-проектов. Там и блоги, и каналы, и курсы :)

  Развернуть 1 комментарий

@denpatin, а в чем заключалась боль?

  Развернуть 1 комментарий

@newarked, а что должно быть? Пост для того, чтобы те кто не в теме, заинтересовались. А ведь есть еще и такие.
Ну а курс - да, и кому-то будет полезно, и мне приятно.

Не очень понимаю, какое ожидание от поста. (Даже если убрать самопиар)

  Развернуть 1 комментарий

@theeremins,

https://habr.com/ru/articles/113913/

Вот эту статью я написал 14 лет назад. Это - вводная статья для тех кто не в теме. Я положил на неё 3 часа. Её до сих пор читают порядка 20 человек в день. Её прочитали пол миллиона раз ПОСЛЕ того, как на Хабре в 2015 году ввели статистику прочтений.

Вводная статья - это не отписка в стиле «есть такое дело». Вводная статя - это «держите, вы попробуете и сможете начать работать, сможете оценить, надо ли оно вам, будете разбираться в азах и понимать, что и зачем.

В программировании любая технология - это инструмент. Подход должен быть такой: «вот урановая отвёртка. Она хороша для откручивание урановых болтов. Её можно для откручивания вольфрамовых болтов. От неё несёт радиацией. Она хорошо, если ты - робот или пришелец. Если ты - человек, рекомендую в костюме защиты. Кстати, урановые отвёртки откручивают обратную резьбу в 3 раза быстрее чем прямую. Урановые отвёртки придумали в 2874 году на Мурлоке потому что им надо было чаще откручивать обратную резьбу. Урановые отвёртки - это странная и опасная технология. Но если вы работаете с обратной резьбой, то вам её необходимо знать».

Понимаете, действование. Что ты можешь ДЕЛАТЬ прямо сейчас с этим. Реальные примеры, а не А плюс Бэ сидели на трубэ. (А примеры у тебя ну просто именно такие вот).

В программировании вообще не бывает технологий, у которых нет никакого бэкфаера. Что-то вкривь и вкось да встанет. Статическая типизация обычно оборачивается жопой в языках, в которых этой типизации нету. Самый яркий тому пример - TypeScript. Теперь все те, кто никогда ничего кроме Яваскрипта в жизни не учил, получили возможность изображать из себя крутых программистов. Те же, кто раньше писал вещи на голанге или шарпах с явой прекрасно знают, что TypeScript - это дикий ужас, если ты пытаешься использовать хоть что-то более чем add(a,b).

Руби, сам по себе, создавался как быстрый язык, который позволяет прототипировать и строить вещи на лету. Он был тем самым языком для "давайте построим самолёт в полёте". Он очень много прощал, и это было нормально. С этого язык и начинался. Динамическая типизация была плюшкой Руби. Руби написали в 1995 году. Тогда большая часть бэка писалась на чистчх Сях.

Ты же приходишь и говоришь: Смотрите, вам нужна статическая типизация в руби. Почему? Это круто! Но на самом деле, вам надо пройти мой курс, чтобы научиться её внедрять. ЭЙФОРИЯ! Всем по статической типизации!

Но это - не ответ. Ответ - это ЗАЧЕМ мне нужна типиация. Что она решает? Чего она НЕ решает. Как её пользовать, и зачем. Что в этом хорошего, а чего - не очень? Вы будете знать как и зачем правильно применять типизацию. Вы поймёте ЗАЧЕМ её изобрели и что этим решили.

https://habr.com/ru/articles/86011/ - вот эту статью про RoR я написал 15 лет назад. Я тогда писал и пробовал RoR. Сейчас я руби не занимаюсь. Но, судя по комментам ниже от народа, тема статической "типизации" в Руби - это дело такое, неясное.

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

Я не против статьи, и ерепенится по поводу твоих ссылок на твои курсы на Вастрике не буду. Я бы даже сказал, что клуб - это как раз место, где можно среди единомышленников эти ссылки проСЕОшить, распиарить и пораздовать.

Я просто к тому, что такие статьи - это на уровне современного Хабра. "Вот вам что-то, что я нагенерил на нейронке, оно вам покажет, куда идти и читать больше нагенерённого текста". В водных статьях нужно больше всего раскрывать.

  Развернуть 1 комментарий

@theeremins, ожидание от поста -- хоть какое-то мясо.

Вот что я прочитал: хуй его знает, чо там типы, может оно вам и не надо. Если вы когда-нибудь складывали два числа, то давайте проверим, что это правда числа и попадаем, если не уверены (нет не давайте, мы для веба пишем, тут все как попало приезжает из непроверяемых статически источников). А еще у руби есть штук восемь проверялок, выбирайте какая нравится сами. Вот мой курс.

  Развернуть 1 комментарий

@s-mage, ну, тем и хороша тема, что ее можно раскрыть. Уверен, что у тебя получится хороший пост с мясом. Скинь потом ссылку

  Развернуть 1 комментарий

@newarked, я очень рад, что ты написал классную статью, аж целых две. Но не очень понимаю, чего же так рвет то от моего поста? Никто нигде не заявлял, что это будет мега обзор с разбором всего.

Возможно, какие-то правила есть, которые я упустил? Ну тогда сорян. Подскажешь какие?

  Развернуть 1 комментарий

@newarked,

Чего она НЕ решает. Как её пользовать, и зачем. Что в этом хорошего, а чего - не очень? Вы будете знать как и зачем правильно применять типизацию. Вы поймёте ЗАЧЕМ её изобрели и что этим решили.

Отличне вопросы. Будет повод мне написать еще одну заметку с раскрытием этих вопросов, ну или тебе погуглить. Что выйдет первым.

  Развернуть 1 комментарий

@theeremins, https://vas3k.club/post/values/

Вот тут, описано. Пишешь посты в самоиар, уж постарайся.

  Развернуть 1 комментарий

@newarked, прочитал. Не увидел, чем краткая обзорная заметка о технологии, в которой еще в первом же абзаце написано, что пост больше про поговорить, противоречит хоть чему-то, что указано в посте Вастрика по ссылке выше

  Развернуть 1 комментарий

Все разы когда я пытался сделать заход в типизацию руби — оно всегда было как–то через жопу. Я до сих пор не понимаю как:
1 аннотировать гемы (не самому же)
2 метапрограммирование

Кроме этого, я так понимаю вывода типов у нас все еще нет. Кажется что за типизацией проще пойти в другое место 🙂

  Развернуть 1 комментарий

@dtsepelev, да, это одни из самых частых проблем:

  1. про гемы - для rbs есть репозиторий rbs-collection в котором есть уже сигнатуры для многих популярных гемов. Уверено, что у shopify есть подобное и для Sorbet. Я больше по RBS. Некоторые гемы сами уже идут с сигнатурами, но это пока редкость. Ну и наконец, не часто нужны детальные сигнатуры гема. Я добавлял RBS в проект и мне нужны были сигнатуры httpparty - по каким-то причинам (не помню) готовые не взял, а за 20 минут накатал краткие на нужные мне get & post методы. Этого было достаточно.

  2. метапрограммирование. Ну, тут как бы тушЕ. Статическое программирование и метапрограммирование несовместимы. Для Rails, например есть rbs-rails gem, который генерирует сигнатуры на основе твоего кода - то есть он сразу создаст все сигнатуры для методов, которые Active Record, создаст тебе на лету, вроде find_by_name, find_by_id etc.

  Развернуть 1 комментарий

@theeremins, к меня ощущение, что отвечал мне LLM 🫠вроде ответил а вроде то же самое сказал
По теме — так может раз основная фича языка несовместима с типами, то пойти в язык с типизацией? Вон хоть crystal

  Развернуть 1 комментарий

@dtsepelev, ну вот, теперь я LLM? 😀 ради любопытства - а что не так с ответом?

Вроде, не ответил разве что про вывод типов. Если правильно понимаю вопрос, то в RubyMine и VS Code есть экстеншены, которые при наведении все покажут

  Развернуть 1 комментарий

Какой оверхед даёт использования Сорбета или аналогов с точки зрения перфоманса?

  Развернуть 1 комментарий

@Frey, подозреваю, что это работает как тайп-хинтинги в питоне или тайпскрипт. То есть, по итогу в рантайме никаких типов нет, а значит и оверхэда. Типы существуют только на этапе разработки в твоей IDE и когда ты явно/неявно запускаешь тайп-чекер перед запуском программы

  Развернуть 1 комментарий

@MrModest, именно так. Единственная. Разница, что Sorbet использует DSL на Ruby, а RBS просто специальный синтаксис в отдельных файлах или в виде комментариев. Ну то есть, к RBS в вопросах производительности, претензий нет

  Развернуть 1 комментарий

@MrModest, в Sorbet есть рантайм-проверка, включается дополнительно. Оверхед от нее, вероятно, есть, но не особо заметный (я специально не мерял).
На работе сорбет используем, сильно жить не мешает, но мы не пытаемся прямо все сигнатурами покрыть.
Не хватает literal types, и inference у него с ограничениями.
Но ошибок типа NoMethodError с ним меньше стало.

  Развернуть 1 комментарий

@wetterkrank, вот да, про "меньше банальных ошибок" я тоже заметил когда начал использовать RBS

  Развернуть 1 комментарий

Страйп заявляет, что никакой потери от использования сорбета нет (я не проверял). Но могу точно сказать что у RBS нет никакой потери как минимум из-за того, как все устроено - у RBS типы это либо обычные комментарии, либо .rbs файлы: которые никак и никем на продакшене не грузятся.

  Развернуть 1 комментарий

😎

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

Что вообще здесь происходит?


Войти  или  Вступить в Клуб