Сервис-классы это счастье. Перепили жирный метод на сервис-класс.
Часики то тикают. Дал бог сервисник — даст и декомпозицию
Сервис классы это действительно охуенно
Давайте для начала определимся с понятиями. Я называю сервис-классом любую
хуйню, у которой нет четкого стейта. Например, какойнибудь
Struct(:name, :type, :content) это определенно не сервисник. А вот
Это определенно сервис, но не сервис-класс. До конца этого поста я буду
называть сервисником именно сервис-классы, а не сервисы вообще.
Да и по жизни тоже
Начнем с простых примеров
Нахуя так делать? Ну в данном нахуй не надо, но пример в целом хороший.
Давайте представим, что кто то умный написал DecimalSum.call("123", %w[456]).
Теперь у нас есть два полноценных метода, объедененных единой логикой
Но нахуя их в сервисник то пихать?
Можно же просто запилить модуль и заинклюдить его вызвать .call на нем
Ну вообще можно, но тут в игру вступает наш главный козырь -
мемоизация
Вот сейчас это уже точно удобнее в виде класса, а не модуля.
Тут правда возникает уже другой вопрос: почему
sum, product = DecimalSumAndProduct.call(params), а не
sum_and_product = DecimalSumAndProduct.new(params); sum_and_prod.sum.
Ответ очень прост: это учебный пример, который не ставил своей целью вернуть
два результата.
А вот этот уже ставит
Это один из самых охуенных API, который можно представить. Но не самый
Генерализация ошибок
Все любять рейзить эксепшены, но не все делают это с любовью. Эксепшен должен
содержать информацию о том, что именно пошло не так. Давайте сравним:
DecimalSumAndProduct#sum наебнулся при попытке сложить 2 и 2,
будучи вызванным из метода #hui
DecimalSumAndProduct#sum наебнулся при попытке сложить 2 и 2,
во время вызова DecimalSumAndProduct.call из метода #pizda
Второй кажется гораздо более информативным в том случае, если [2, 2] это
не особо валидное значение для @args и
эксепшен надо бы бросить тому, кто придумал это в наш сервисник сувать.
Потому что накосячил именно метод #pizdaВ сервисниках, косячит либо сервисник, либо тот кто передал ему параметры.
Благоразумно выполнять всю работу при первом вызове, если ленивость не входит
в изначальную задумку
Обобщайте ошибки
Все ошибки, вызванные херовыми параетрами / кривым стейтом / чем то другим,
не зависящим от корректности работы модуля (в нашем случае,
просто одинокого сервисника), принято заворачивать в его родные ошибки.
Это просто полезно, если подходить к вопросу без фанатизма
Технически, нормализацию переменных тоже уже можно вынести отдельно.
Так и сделаем
Очень выразительно, не правда ли?
Ну и наконец
Я покажу пример с использованием гема
polist, который реализует все эти
паттерны