Рефакторинг кода для условий среды в приложении Rails

#ruby-on-rails #design-patterns #refactoring #sidekiq

#ruby-on-rails #шаблоны проектирования #рефакторинг #sidekiq

Вопрос:

В моем приложении Rails я использую sidekiq для планирования заданий для выполнения тяжелых задач. Итак, у меня есть этот код во многих местах:

 if Rails.env.development? or Rails.env.test?
   #Call the method directly
else #Rails.env.production?
   #Call the job via sidekiq that calls the said method
end
 

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

Комментарии:

1. Общего ответа нет — это зависит от характера вызываемого, является ли оно частью иерархии классов и т. Д. Похоже, что какая-то форма микширования может обернуть это, например, форма sidekiqable :the_method оболочки.

2. Вы думали об использовании just jobs? Вы можете установить разные исполнители заданий в соответствии с вашим env (sidekiq для prod, async для dev и test для test) для достижения аналогичного поведения, и было бы меньше кода, специфичного для среды, который менее подвержен ошибкам. Я предполагаю, что прямо сейчас ваши тесты проверяют вызовы методов, но что произойдет, если ваша работа изменится, и вы забудете обновить? Все тесты проходят, но ваш фактический производственный код прерывается.

Ответ №1:

Вы можете поместить

 require 'sidekiq/testing'
Sidekiq::Testing.inline!
 

в ваших development.rb и test.rb конфигурационных файлах, чтобы получить поведение, которое вам нужно. В бизнес-логике ваших приложений вы должны удалить условие среды и просто вызвать worker (который теперь будет выполняться синхронно при тестировании и разработке).

Ответ №2:

Как насчет того, чтобы попробовать рефакторинг следующим образом?

 module Util
  extend self

  def execute_method_or_delay_its_execution(obj:, method_name:)
    if Rails.env.development? or Rails.env.test?
       obj.send(method_name)
    else #Rails.env.production?
       #Call the job via sidekiq that calls the said method
    end
  end
end

MyClass1
  def my_method
    Util.execute_method_or_delay_its_execution(obj: self, method_name: :my_method)
  end
end

MyClass2
  def my_method
    Util.execute_method_or_delay_its_execution(obj: self, method_name: :my_method)
  end
end
 

а затем просто вызовите методы для объекта, как и должно быть, и внутреннее делегирование должно позаботиться о желаемом прямом выполнении или отложенном выполнении

 mc_1 = MyClass1.new
mc_1.my_method

mc_2 = MyClass2.new
mc_2.my_method
 

Надеюсь, это поможет. Спасибо.

Комментарии:

1. Наличие условия, которое вызывает метод, прямо противоположный прохождению через worker, является очень опасной игрой, если ваша команда инженеров не очень в курсе событий, потому что методы / сервисы будут взаимодействовать по-разному в зависимости от вашей среды. Например, при производстве результатом этого метода будет строка (задание sidekiq), тогда как при разработке / тестировании результатом этого метода будет все, что возвращает отправленный метод.