Есть ли жизнь после Rails?

Samoilenko Yuri
rnds
Published in
4 min readOct 2, 2020

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

Несколько лет назад в нашей компании появился “микросервисный” проект. Настолько микросервисный что ТЗ так и звучало: “есть много сервисов — надо чтобы они все работали”. Поскольку основной стек технологий у нас базируется на руби, мы и начали делать все сервисы на руби. В процессе работы у нас появилось что сказать по этому поводу и скоро будет чем поделиться. Так как же чувствует себя руби, когда сходит с “рельсов”?

Что нам нравится?

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

Скорость разработки

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

Простота

Работать этот сервис будет хорошо, код получится понятный. Переписать или изменить его будет очень легко. Ну это если вы, конечно, сделали его “микро”.

Обилие библиотек

У руби очень большое сообщество, огромное количество библиотек — уже есть решение на все случаи жизни.

Тесты

Огромнейший плюс языка это его гибкость и наличие великолепного фреймворка для тестирования RSpec. Писать тесты — одно удовольствие. Сейчас мы вполне успешно поддерживаем в актуальных библиотеках и сервисах покрытие юнитами в 99%.

Наша внутренняя библиотека для работы с AMQP

А если говорить про интеграционное тестирование то мы даже сервисы написанные на Gо “интегрируем” на руби — порождать процессы легко, управлять ими, делать с ними всякое… Ух
В общем всем рекомендую.

Интерпретируемость

Как бы странно это не звучало, но в сервис на руби всегда можно “зайти” и на горячую его подправить. Без этих ваших деплоев. Конечно не стоит так делать на проде, но жизнь есть жизнь и на тестовых стендах это получается очень удобно. Компилируемые языки похвастаться такой свободой не могут — собирай их, пакуй их, публикуй, деплой…

С чем пришлось смириться?

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

Макросервисы

Никакие это не микросервисы! Минимальный контейнер 300mb на альпайне и 500mb на убунте. А если вдруг вам потребуется веб-интерфейс в сервисе то это уже от 800mb!

“простой” сервис и сервис с веб-интерфейсом

Скорость сборки

Сборка образа это долго. bundle install это долго. Если у вас там nokogiri с компилируемым расширением, то надо сначала поставить весь toolchain с компилятором, потом забандлить и собрать зависимости, потом удалить компиляторы и все это в одном слое… В плохих вариантах это занимает 15 минут. С этой проблемой можно бороться, но с переменным успехом. Мы используем базовые образы с предустановленными гемами и разнообразными библиотеками (gettext, libpq, libxml) которые требуются большинству сервисов. Образы получаются потяжелее, но зато сборку реально ускорить до 2–3 минут. Кроме того базовые образы общие между большинством сервисов и это сильно уменьшает объем реально передаваемых данных.

Штатный билд сервиса

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

Утилита — вовсе не утилита

Даже маленькая утилита, написанная на руби — вовсе не утилита, а целый пакет. Чтоб её использовать надо ставить интерпретатор, тянуть зависимости из интернета, а в ДМЗ-контурах заказчика это совсем не просто. Вот замечательный Python умеет паковать все в один исполняемый файл (например docker-compose) и это замечательно. Да большой, зато удобно.

Отсутствие Rails

Мы начали жить без rails, но весь наш проект не стоит на месте — сервисы эволюционируют и развиваются. Они перестают быть прототипами, обрастают конфигурацией и параметрами, работой с базами данных и всякими инициализаторами, метриками, логированием и прочими атрибутами Ынтерпраза. В нашем случае мы работаем с RabbitMq, Redis, Postgres, ELK, prometeus, consul и другими компонентами. Чтоб как-то с этим справляться мы реализовали свои соглашения, свои подсистемы конфигурирования (через переменные, файлы, consul или valut), инициализаторы, eager_load кода в продуктовом режиме и многое другое. У нас в полный рост используются ActiveSupport, ActiveModel, ActiveRecord и даже ActiveJob. Все это достаточно просто и, местами, красиво, но в результате мы получили собственный фреймворк а-ля Rails только без папки “controllers”. Теперь есть стойкое, необоримое желание перебраться обратно на “рельсы” чтобы все было понятно и по канонам.

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

До новых встреч!

--

--

Samoilenko Yuri
rnds
Editor for

Lead developer and technical writer @ RNDSOFT // Ruby 💕