Переход от бессерверного проекта к Ruby on Rails
Перевод статьи “Moving my serverless project to Ruby on Rails”
Алекса Котлярски от 14 ноября 2020 года.
У меня есть маленький сторонний проект: подарочные карточки для хакеров hacker gifts. Он использует Shopify для всего что связанно с продажей: внешний вид, оплата, возвраты, отчеты и пр.
Но в отличие от обычных цифровых товаров (электронные книги, видео) мне хотелось сделать уникальной каждую карточку, которую покупает пользователь. Для этого я написал скрипт создания персонализированных картинок и запускал его вручную для каждого заказа.
Следующим шагом была автоматизация. Я подключил услугу бессерверных вычислений AWS Lambda. В то время это была новая технология и мне хотелось узнать про неё побольше. Мне казалось что она очень хорошо ложится в мой кейс: функция с одной ответственностью, которая может запускаться в любое время и не требует поддержания сервера.
Сначала всё было очень просто. Я написал JavaScript функцию, задеплоил её на AWS Lambda, добавил веб-хук в Shopify и всё заработало!
Начальные преимущества от бессерверных вычислений (для домашних проектов):
- Легко начать
- Не надо настраивать и поддерживать сервера
- Бесплатно для небольшой нагрузки
Но в действительности написание простых Lambda-функций обернулось лишь десятью процентами работы.
Время шло и бэк становился сложнее. Понадобилось хранить состояния для каждой головоломки, рассылать письма, показывать информацию по заказам. То, что началось с одной простой функции выросло в целую кучу бессерверных функций, SNS-топики, S3-бакеты и таблицы в DynamoDB. Всё связывалось вместе YAML-клеем, бесструктурными JSON’ами то там то здесь и какими-то зашитыми конфигами в панели управления AWS.
На мой взгляд это обычный жизненный цикл ПО: функционал усложняется, становясь запутаннее и потом требует рефакторинга. Сначала нужно просто запуститься (исследовать потребности рынка), а затем сделать правильно (отрефакторить в соответствии с новыми требованиями).
Но в этот раз всё было иначе. Я не мог взять и просто отрефакторить всё так же как в традиционном монолитном приложении. Вот почему:
Когда части системы очень простые, то сложность системы сдвигается в область взаимодействия частей.
Но взаимодействие между бессерверными частями происходит вне моего приложения. Lambda-функция публикует сообщения в SNS, другая подхватывает его и пишет что-то в базу, третья берёт эту запись и отправляет email…
Я могу протестировать каждую отдельную часть этого процесса, но у меня нет уверенности в процессе целиком. Что если сообщение не дойдёт до очереди, как мне узнать об этом? Как система будет восстанавливаться? Как мне откатиться и попробовать заново? Где искать логи?
Другой ворох проблем прятался в конфигурации: bad Route 53 (DNS от AWS), опечатки в имени SNS-топика, ошибка в регионе бакета S3. Поиск ошибок был очень сложен, потому что нет единого лога, где можно поискать проблему.
При бессерверных вычислениях вы уже не работаете со своим приложением, вы работаете с распределённой системой.
В этот момент я почувствовал себя обманутым.
Я купился на простой деплой и возможность не думать о сервере, но в конце мне пришлось проектировать систему с учётом всех ограничений платформы.
Недостатки бессерверных вычислений (для домашних проектов):
- Тяжело следовать за потоком обработки информации
- Невозможно воспроизвести окружение локально
- Низкая скорость выпуска новых версий продукта
- Невозможно осуществить сквозное тестирование
- Слабая документация (зачастую в устаревших постах на Medium)
- Отсутствие соглашений (приходится принимать сотни незначащих решений)
Да и просто не было никакого удовольствия от этой бессерверной работы. Поэтому я решил всё переписать — ведь это домашний проект, который я делаю ради своего удовольствия. Выбор пал на Ruby on Rails.
Я не пользовался Rails с 2013 года и в течении восьми лет в Facebook я в основном занимался JavaScript’ом.
Опыт переезда обратно на рельсы был хорош, но…. Без происшествий. Изменилось немного: кое-что добавили, кое что изменили.
Конечно пришлось столкнуться с некоторыми магическими проблемами в Ruby. Но в отличие от аналогичных вещей в JavaScript, решения находились очень легко.
Rails поставляется с огромным количеством встроенных и настроенных фич. В JavaScripte мне приходилось пользоваться случайными библиотеками и согласовывать их чтобы сделать необходимый вещи: роутинг, обертки над файловыми хранилищами, предпросмотр писем, управление ключами, фреймворк с тестированием, миграции базы, логирование, метрики производительности, скрипты деплоя. С Rails я могу вообще не думать об этих деталях и сконцентрироваться на создании ценности продукта.
Это как сесть за Теслу, после нескольких лет ручной сборки машины из запчастей. Всё тоже состоит из запчастей, но отлаженных и хорошо состыкованных для совместной работы.
Преимущества от Rails (для домашнего проекта):
- Соглашения
- Инструментарий и библиотеки
- Документация
- Монолит который легко понять и протестировать
Недостатки Rails (для домашнего проекта):
- Слегка тяжеловато для начала
- Больно, если ты отходишь от соглашений
- Необходим сервер
- Звучит не круто в 2020 (уже не круто или возможно пока)
Бессерверные вычисления как чёрная дыра. Обещают быть увлекательным путешествием, но гравитация притягивает и приходится большую часть усилий тратить на преодоление сложности, вместо того чтобы сконцентрироваться на продукте.
Не знаю как вам, а мне эта статья очень зашла. Она как-то ложится сейчас в намечающийся тренд Rails Again. Чуть позже думаю будет более детальное изложение мыслей на этот счёт.
Оригинал: Moving my serverless project to Ruby on Rails от 14 ноября 2020 года.
Автор: Alex Kotlyarskiy