Сервисный объект ил...
 
Уведомления
Очистить всё

Сервисный объект или метод модели: спорим на ревью уже третий PR

7 Сообщения
6 Пользователи
14 Реакции
539 Просмотры
Валерий40
Сообщения: 33
Автор темы
Читает чужие PR фулстек-разработчик
Присоединился: 4 года назад
[#78]

Принёс спор на суд. По старой привычке с Laravel выношу логику в сервисы, а коллега на ревью каждый раз просит вернуть её в модель. Пример, отмена заказа:

class CancelOrder
  def self.call(order, reason:)
    new(order, reason).call
  end

  def initialize(order, reason)
    @order = order
    @reason = reason
  end

  def call
    return false unless @order.cancelable?

    @order.transaction do
      @order.update!(status: :canceled, cancel_reason: @reason)
      @order.items.each(&:release_stock!)
    end
    OrderMailer.canceled(@order).deliver_later
    true
  end
end

Коллега говорит, что это order.cancel!(reason) и десяток строк в модели. Я отвечаю, что Order и так 600 строк. Кто прав?


6 ответов
kostya.sokurov
Сообщения: 73
Держит прод бэкенд-разработчик, senior
Присоединился: 4 года назад

Я тут скорее на стороне коллеги, и не из принципа. Отмена заказа это поведение заказа, и order.cancel! читается естественно. Если модель 600 строк, проблема не в отмене, а в том, что в ней живёт ещё десять тем сразу. Её можно разрезать на concern'ы по смыслу, и тогда отмена лежит в Order::Cancellation:

module Order::Cancellation
  extend ActiveSupport::Concern

  def cancel!(reason)
    return false unless cancelable?

    transaction do
      update!(status: :canceled, cancel_reason: reason)
      items.each(&:release_stock!)
    end
    OrderMailer.canceled(self).deliver_later
    true
  end
end

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


Ответ
1 ответ
Валерий40
Присоединился: 4 года назад

Читает чужие PR фулстек-разработчик
Сообщения: 33

Автор: kostya.sokurov
Тогда у неё нет естественного хозяина.
Вот формулировка, которую я искал. Вернул отмену в модель через concern, как в примере, коллега одобрил с первого раза. А оплату, которая ходит в платёжку и в складской сервис, оставил сервисом, и тут спора уже не было.


Ответ
artem_67
Сообщения: 18
Пишет тесты разработчик на Go
Присоединился: 4 года назад

в Go это была бы функция CancelOrder(order, reason), и спора бы не было


Ответ
1 ответ
Егор64
Присоединился: 3 года назад

Читает чужие PR тимлид
Сообщения: 30

Автор: artem_67
в Go это была бы функция
Так сервис с одним методом call это и есть функция, только в рубиновой обёртке) Спор же не про синтаксис, а про то, где человек будет искать этот код через год.


Ответ
alisher1996
Сообщения: 6
Пишет в irb архитектор
Присоединился: 3 года назад

Самое рабочее правило, которое я видел: если метод меняет только саму запись и её дочерние, он в модели. Если трогает чужие агрегаты или ходит наружу, это сервис. Споры на ревью заканчиваются, когда правило записано в README команды, а не живёт в головах.


Ответ
slava52
Сообщения: 9
Разобрался с блоками middle-разработчик
Присоединился: 2 года назад

Пришёл из C# и сначала тоже всё складывал в сервисы. Со временем почти всё переехало в модели, кода стало меньше


Ответ