Привет! Меня зовут Вероника Молчанова. Я - Ruby-разработчик в компании Joy Dev. В этой статье мы рассмотрим набор Ruby-библиотек dry-rb и расскажем, как они помогли упростить архитектуру проектов. В частности хотим показать, как на наших проектах используются такие гемы из dry-экосистемы, как: dry-auto_inject dry-validation dry-struct Один из принципов Ruby on Rails заключается в использовании механизмов, минимизирующих дублирование кода в приложениях - принцип Don’t repeat yourself, DRY. Принцип DRY позволяет построить модульную архитектуру приложения и чётко разделить ответственность за бизнес-логику между программными классами. Однако следовать этому принципу в рамках больших проектов не так просто, как это может показаться на первый взгляд.  На собственном опыте мы убедились, что dry-rb хорошо справляется с задачей декомпозиции сложных операций на более простые и значительно облегчает понимание программного кода. В dry-rb входят более 20 гемов, которые помогают реализовать различные задачи. Более подробно с каждым из них вы можете ознакомиться в официальной документации: https://dry-rb.org/ В этой статье хотим выделить наиболее практичные инструменты, которые мы внедрили в проекты и используем на постоянной основе.  dry-auto_inject DI (Dependency Injection, внедрение зависимостей) — это эффективная идея, благодаря которой возможно обрабатывать зависимости вне зависимого класса. Внедрение зависимостей — это то, что позволяет комбинировать небольшие компоненты для создания более сложного поведения. С использованием гема dry-auto_inject процесс упрощается. Вместо создания конструкторов или методов доступа необходимо всего лишь добавить дополнительные зависимости.  Для того, чтобы использовать dry-auto_inject, после установки гема в директории config/initializers/auto_inject.rb создаём класс-контейнер и настраиваем модуль DI: Этот класс включает в себя контейнеры из различных модулей приложения. Для удобства мы их распределили в отдельные файлы. Регистрируем Query-объекты под определенным пространством имён:  После того, как все контейнеры описаны, подключаем настроенный модуль DI для класса, использующего зависимости. Например: Модуль, подключаемый с помощью include DI[*dependencies], определяет из контейнера зависимость и позволяет использовать её под указанным именем. Предварительно создав контейнер, мы можем зарегистрировать объекты один раз и в дальнейшем многократно использовать их в различных частях приложения.  Кроме того, имеется возможность простого обновления списка зависимостей. dry-validation Фреймворк Ruby on Rails предоставляет стандартные методы для валидации входных данных в моделях. Однако если требуются дополнительные проверки или список параметров варьируется, то класс модели будет нечитабелен из-за огромного количества кода для валидации.  Альтернативой может служить гем dry-экосистемы dry-validation. С помощью этого гема мы можем вынести логику валидации в отдельные формы или контракты, которые состоят из параметров, описывающих условия проверки каждого из них, и кастомных правил. Правила можно описывать в самой форме, но на практике оказалось удобнее выносить их в отдельные макросы. Так мы можем определить правило один раз и использовать его в нескольких формах без дублирования кода. В родительском классе ApplicationForm описываем конфигурацию для локализации ошибок и включаем все используемые макросы: Чтобы валидация параметров была удобней, мы прописали concern для контроллеров с помощью форм. Метод validate_with проверяет, вернула ли форма ошибки. В случае успешной валидации он возвращает хэш с проверенными параметрами. Вызов этого метода в контроллере выглядит следующим образом: valid_params = validate_with(create_form, params) В данном случае create_form - это зависимость формы, подключение которой мы рассмотрели ранее с помощью dry-auto_inject. Использование гема dry-validation обеспечит эффективную настройку среды для валидации входных параметров без дополнительной нагрузки классов-моделей. dry-struct Бывают ситуации, когда необходимо указывать в методе большое количество передаваемых параметров. Ruby позволяет использовать параметр **kwargs, который передаёт аргументы переменной длины с ключевыми словами.  Однако если вы работаете на крупном проекте, при использовании **kwargs сложно отследить, какие параметры необходимы тому или иному методу.  В этом случае на помощь приходит гем dry-struct.  В структуре описываются все необходимые атрибуты, их типы и значения по умолчанию. Стоит отметить, что dry-struct не имеет возможности валидировать параметры, как это делает dry-validation, поэтому этот гем стоит использовать только для структурирования данных. Инициализация структуры выглядит следующим образом: Создаём структуру с параметрами, первоначально проверенными формой. И затем передаём эту структуру в необходимый метод.  Таким образом, используя объект структуры в качестве параметра методов, мы избегаем длинных списков параметров и добиваемся большей читабельности кода. В этой статье мы описали далеко не все преимущества dry-экосистемы. Нашей целью было показать вам, что с помощью гемов можно реализовать архитектуру, удобную в работе над крупными проектами.  Валидация, структурирование, внедрение зависимостей - это возможности, которые вы легко и просто настраиваются благодаря инструментам, предоставляемым dry-rb. Backend-разработчик