Обновить

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

Явные контракты — теперь мы чётко видим и понимаем, какие данные принимает приложение при создании заказа и какие данные возвращает

StoreOrderFeatureTest

app/UseCases/V1

StoreOrderHandler

testUserCanCreateOrder

у разрабов на laravel какая то особая тяга к хаосу.

  • фичатест тестирует контроллер, а не фичу

  • фича - сохранить заказ (не обработать, не принять, не поставить в очередь на обработку)

  • название тест метода говорит чтт проверяется то что пользователь может ссоздать заказ, хотя фича сохранить заказ

  • фича сохранить заказ проверяется в тесте контроллера апишеи, который проверяет может ли пользователь создать заказ

  • фича сохранить заказ = обработать запрос "сохранить", вызвав обработчик сохранения заказа, который на самом деле юзкейс

  • тест фичи "сохранить заказ" проверяет что "пользователь может создать заказ", проверяя что "после вызова запроса апи от юзера 1 в базе есть заказ юзера 1"

плавает как утка, крякает как дятел, ведет себя как покемон, но в целом - енот охотничей породы

Тестирование UseCase? - это ещё проще!
В данном случае я советую писать тесты которые проверят работоспособность вашего бизнес-процесса.

барабанная дробь... да, тестируется именно контроллер, все эти юзкейсы инпуты аутпуты были зря.

вопросы:

  • а зачем тогда вам были нужны все эти церемонии с выделением input/output/handler?

  • что, кроме бессмысленных в приведенном примере 3+ классов, вы потеряете в этом случае, если контроллер просто сохранит заказ из данных полученных в запросе?

  • как вы собираетесь использовать версионирование юзкейса "сохранить заказ"? будет ли ситуация что их 2 параллельно работают?

учиться и учиться!

Большое спасибо за прочтение и за ваш комментарий!
Остальные классы вы также можете протестировать)
Да контроллер может сохранить заказ без проблем!

Все мы учимся!

Капец. Если б не ваша статья я бы считал что usecases я сам придумал неделю назад. Я их назвал прям так же. Использовал схожим образом. И был настолько рад этой идее что мне даже не пришло в голову нагуглить что-то подобное:)

Большое спасибо что прочитали)

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

Почитайте про Vertical Slice Architecture (VSA).

Почему то в ру сегменте подход, и информация о нем, слабо распространены.

Спасибо, обязательно посмотрю!

Если не считать того, что Rational Unified Process был опубликован, кажется, в 1998, и, следовательно, прорабатывался в целом в конце прошлого века, и да, там есть юз кейзы, вы оба молодцы. :)

😂😂😂

Большое спасибо)

Так то usecase не должны возвращать результаты, результат выполнения события, посмотрите видео с DrupalCon которому уже 10лет, там все подробно разложено https://youtu.be/ajhqScWECMo

Большое спасибо что прочитали статью)

Не могу отрицать такие реализации тоже имеют место быть, но в данном случае мы работаем с restAPI приходиться что-то возвращать)

Если речь о Rest API, то в некоторых случаях можно возвращать 204 No Content :)

Имхо ситуация отличается от проекта к проекту, тут сложно предугадать.

Если можно сформировать DTO'шку из текущего агрегата, почему этого не сделать? Такой код не будет делать лишние запросы в базу и, скорее всего, его будет просто понять. Тут скорее важно только где и как вы мапите в DTO и что бы сам агрегат не был слишком раздут.

С другой стороны, если так поступить не получится, придётся обращаться к CQRS, который, как тут недавно писали, нарушает DDD, и делать запрос из ReadRepository.

Поэтому имхо баланс очень важен.

Согласен с вами полностью!

Когда мы ничего не возвращаем наша архитектура становится похожа больше на команды CQRS паттерн.

Но даже самые смелые возвращают id записи чтобы была возможность у фронта обратиться за получением, либо прибегают к использованию websocket чтобы получить тот или инное событие системы.

Был у нас такой юзкейсер, до сих пор разгребаем..)

Большое спасибо что прочитали статью)

Если не секрет что конкретно разгребаете? С какими проблемами столкнулись?

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

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

Что бы знать, что делает приложение, в 90% случаях достаточно посмотреть на точки входа, разве нет? Оставшиеся 10% это какие нибудь бекграунд джобы.

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

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

Полностью с вами согласен!

1. Вот был у меня UseCase - создание приглашения о присоединении к системе для пользователя (в табличку запись добавляется, пользователю письмо улетает).
Потом появился новый сценарий - принятие запроса на временное присоединение к пространству пользователя специалиста поддержки, в который так же входит отправка приглашения пользователю (в табличку запись добавляется, пользователю письмо улетает). Теперь мой первый UseCase - уже не UseCase, если это часть другого UseCase? Что мне делать с "последовательностью управляющих конструкций"? Продублировать в двух UseCase'ах? Вынести код из первого UseCase в разделяемый сервис/модель? Вызвать один UseCase из другого?

2. Если сервисы делать маленькими, то это уже UseCase'ы?

Большое спасибо что прочитали статью!)

  1. Вы можете вынести общую логику в сервис, и сервис уже подключить в двух UseCase. Использовать один UseCase в другом UseCase лучше в самую последнюю очередь.

  2. Маленькие сервисы это не UseCase. Размер класса не определяет его роль. UseCase - это один конкретный бизнес процесс, бизнес сценарий. А Service это переиспользуемая бизнес-логика, т.е. часть какого-либо сценария.

Ну и в чём тогда выигрыш. Вот мы разложили всё по "сервисам" - переиспользуемую бизнес-логику и "use-case'ы" - конкретные бизнес-сценарий. У нас система развивается и "конкретный бизнес-сценарий" превратился в "переиспользуемую бизнес-логику". Так что границы между этими понятиями, которые мы для себя нарисовали, оказались весьма условны.

Граница между Service и UseCase действительно условна. Но цель UseCase не в строгой классификации классов. Его задача сделать структуру приложения отражением бизнес-сценариев системы.

Статья напомнила мне об архитектурном паттерне Porto, с которым я недавно познакомился. Porto — это значительно более широкая концепция, нежели просто use cases: она описывает полноценную архитектуру приложения с чётким разграничением зон ответственности между компонентами.

Тем не менее, раздел про Actions и Tasks в документации Porto перекликается с идеями из этой статьи — там подробно описано, как декомпозировать бизнес-логику и куда её помещать.

Всем, кого заинтересовала тема, рекомендую ознакомиться с разделом «Components» в официальной документации Porto — думаю, это даст более широкий контекст для понимания подобных подходов.

Большое спасибо что прочитали статью)

Обязательно почитаю про данный подход, спасибо!)

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

Публикации