Как стать автором
Обновить

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

Сервис — это координатор, а не исполнитель

,

Модели — не свалка для методов

А где ж тогда код большой бизнес-логики хранить, если не в моделях и не в сервисах?

Понятно, что генерация эксель-отчетов может быть отдельным сервисом, но если требуется куча статистики по разным алгоритмам, куда это пихать, если не в длинный StatisticService? В котором будет 5-6 300-строчных методов на каждый алгоритм статистики.

А что будет делать StatisticService? Если он и собирает данные, и преобразовывает их как-либо, вычисляет что-то, кладет в базу, то конечно это божественный класс и так лучше не делать и делегировать задачи другим классам. Конечно не стоит плодить сущности ради сущностей, любым принципом можно пренебречь. В целом хочу напомнить, что это лишь рекомендации, а не правила, вы можете писать так, как вам и вашей команде удобно)

вероятность смены базы данных

Эту теоретическую ахинею я слышу уже наверно лет 15 - что кто-то зачем-то будет в легаси-проекте менять базу данных. После пары-тройки лет вы уже и фреймворк просто так не обновите (масса зависимостей и клиентский код под конкретную версию фреймворка), о какой смены базы речь?

Контроллер должен

Опять сухая теория (как и статья), что-то вроде размышления советских людей о коммунизме.

На практике иногда легче наговнокодить в контроллере и забыть об этом участке кода на несколько лет, чем писать 5 слоев абстракции и сервисы с одним методом, которые больше никто и никогда использовать не будет. Недавно код вычищал, как раз умники, начитавшись умных книжек, породили 100500 классов только потому, что так им сказали в этих умных книжках. В итоге все свелось к одной строчке кода.

Основной принцип, который должен быть в архитектуре ПО - KISS, что бы и ты спустя время разобрался и "человек с улицы". Все остальное нужно добавлять по мере необходимости. Если ваш контроллер использует

User::where('is_active', true)->get()

то ничего смертельного нет, если вы не обернете эту строку в череду классов и абстракций. А вот проект, который на основе умных книжек разрастается до уровня монстра - это страшно.

Как и написано в конце, ко всему нужно подходить с умом) Конечно, иногда можно забыть о всех правилах, иногда нельзя, решать вам, я лишь показал, как можно делать и как это делать рекомендуют.

Несколько раз встречал смену БД. И с ms SQL на postgres из-за импортозамещения. И с всякой экзотики потому что это экзотика.

Но слой совместимости создавался после того как начинался переход. Заранее такой фигнёй никто не занимался. И это правильно.

На практике иногда легче наговнокодить в контроллере и забыть об этом участке кода на несколько лет, чем писать 5 слоев абстракции и сервисы с одним методом, которые больше никто и никогда использовать не будет

Иногда да, иногда нет)

Основной принцип, который должен быть в архитектуре ПО - KISS, что бы и ты спустя время разобрался и "человек с улицы".

Как только узнаю на собеседовании, что в компании подход к проектированию архитектуры по принципу типа "чтобы разобрался вчерашний студент с улицы", то сразу понимаю, что время на такую компанию тратить не хочу.

Потому что понятно, откуда ноги растут, какая там текучка и т.п.

Отличный индикатор, который экономит время соискателей.

Типичный случай смены базы - моки для запуска тестов. Просто иногда без тестов банально страшно выкатывать продукт. А если ваш контроллер вызывает User::where('is_active', true)->get(), то такой код протестировать трудно.

На практике иногда легче наговнокодить в контроллере и забыть об этом участке кода на несколько лет

Ну да. Потом искать такие участки столько же)
Статья про контейнеры/слои. Если стоит задача показывать юзеров ещё и с номером телефона? Полезешь в "наговнокоженное" место, которое написано в 10+ местах, чтобы
User::where('is_active', true)→get()
поменять на
User::where('is_active', true)→whereNotNull('phone')→get()
Тяжело же просто сделать →onlyWithPhone()

Учебники для этого и пишут, чтобы кодить правильно, а не одни и те же action's по проекту размазывать.
Ну, зато тебя человек с улицы лучше понимает)

Немного духоты вам в комментарии :)

Чего не final'ите OrderDTO? От него же никто по идее не должен наследоваться. Так же, как мне кажется, код был бы чище если бы использовалось https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor.promotion

Repository - это класс, куда мы выносим какую-либо логику работы с базой данных. Чаще он используется для приложений, где есть вероятность смены базы данных.

В первую очередь это даёт нам low coupling - то, к чему мы все всегда стремимся, а уже low coupling даёт возможность сменить БД без танцев с бубном.

И я правильно понимаю что FilterDataForInsertAction это интерпретация https://refactoring.guru/ru/design-patterns/command ??

Спасибо за дополнение! Пока не выработал привычку финалить классы, обязательно исправлюсь, но да, от него не должны наследоваться. Action`ы, по крайней мере в Laravel (пример контроллера, пример экшена) обычно не используют ещё одну абстрактную прослойку, как указано в статье, что вы приложили, но суть та же.

Я в IDE настроил шаблон, все классы теперь изначально final :) Шаблон экономит время

Итого выходит почти DDD. В целом предложение очень хорошее. Смена БД, как тут хейтили, встречается часто, но смысл именно в SRP в первую очередь. Сразу добавлять эти классы легко, это 5-10 процентов на задачу. А самое важное в результате - это легко читаемый проект, легко расширяемый и легко поддерживаемый.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации