Pull to refresh

Comments 16

У медиатора есть преимущества

  • Крайне удобно писать юнит тесты, то есть можно закинуть в IProcessorBuilder реквест и во всех тестах делать _mediator.Send(_request.Create());

  • Так как все handler'ы идут сразу за controller'ом можно удобно определить какая общая бизнес логика нуждается в выносе в универсальный сервис. В обычном сервисе так и хочется вынести в приватный метод

  • Удобно использовать в WPF, потому что каждый handler резолвит под своим скоупом, что даёт возможность не следить за using'ами

И туча недостатков - от общей каши в коде, до pipeline behaviors, что являют собой какое то лютое зло прямиком из ада

Лично я перестал использовать MediatR и не жалею. Очень улыбнула статья, напомнила одного моего коллегу, который выражал те же мысли. Но, в итоге, MediatR подтолкнул нас к созданию элегантного решению с шаблонами, так что, думаю, польза есть и весьма весомая в обучающем смысле ;)

Почему pipeline behaviors - это зло, и как лучше сделать логирование контекста или повтор всей application layer транзакции для произвольного, постоянно меняющегося интерфейса методов-команд, которые используются произвольными же клиентами - ASP.NET, RabbitMQ, Quartz.NET etc? Bridges до middleware-функциональности driving-адаптеров? Кодогенерация декораторов? DynamicProxy?

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

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

От того же автомаппера практически везде отказались в пользу обычных классов-адаптеров, оставив только простейшие DTO->DTO маппинги(для чего он собственно и предназначен). Страшно подумать сколько маппингов для него присутствует в разных легаси(и не очень) проектах, с целыми портянками конфигурации и без тайпчекинга(удачи дебажить в рантайме).

А можно привести какой нибудь пример применения автомаппера для чего либо кроме DTO->DTO маппинга и как это заменяется адаптерами? А то я не очень представляю, что с ним можно кроме дтошек маппить )

Большинство минусов MediatR от неправильного приготовления. Если взять за правило _mediator не может вызываться из хендлера, единственное место вызова медиатора - контроллер, request и handler лучше писать в одном файле т. к. на один request может быть только один handler, тогда большинство минусов уйдёт. Но получаем огромный плюс в виде того, что каждый endpoint теперь обрабатывается в отдельном файле, а значит разработчики меньше пересекаются при разработке и меньше конфликтов

Но получаем огромный плюс в виде того, что каждый endpoint теперь обрабатывается в отдельном файле

До тех пор пока не возникает двух команд с большим куском одинаковой логики. Добавление/обновление, например.

А создать несколько сервисов вместо одного, чтоб не пересекаться, можно и без mediatr, непонятно в чем проблема

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

Я вот встречал, что начинают в один handler пихать несколько команд и проблема встанет ровно такая же, если не хуже.)
В сервисе хотя бы есть возможность сделать приватную общую часть, если нужно, а в mediatr как поступать, если есть несколько похожих команд?

Никто не мешает вынести общую часть в сервис и прокинуть его в хендлер

Ну никто не запрещает сделать базовый хендлер. Обрабатывающий команды добавления.
А уникальный код вынести в наследники.

На ровном месте добавлять наследование ради чего? Чтоб медиатр заиспользовать? Что то выглядит не очень

Полностью согласен с @VanKrock. Мне кажется, что хэндлер нужно воспринимать как некий Transaction Script, который вызывается в одном конкретном месте.

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

Если же появляется повторяющаяся задача, то выносим ее в отдельный сервис бизнесс-логики. Вроде бы по классике все…

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

Request и Handler в одном файле и в одном проекте полностью противоречат Clean Architecture, нарушают принцип DIP, и в целом, как уже сказано, никаких принципиальных отличий нет от:

_serviceProvider.GetService<IHandler<MyCommand>>().Handle(command);

Никаких, только чуть больше букв. И это по сути Service Locator, что является антипаттерном.

Использование IMediator не позволяет проследить зависимости, построить диаграмму классов, вообще увидеть что от чего зависит и увидеть нарушения SRP.

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

Большинство минусов в забивании гвоздей микроскопом -- от неправильного приготовления. Главное правильно ухватиться и правильно бить. Всё будет хорошо :)

Мой проект на ddd со слями итд и тп и вот стало скучно, решил медиатоР прикрутить, один сервис заменил им и вот не доходят руки в кинуть его обратно... Не могу понять фанатов этой библиотеки.

У нас был чувак, который до нас по tdd работа и они активно юзали библиотеку, он вздрагивал как только слышал mediatR

Sign up to leave a comment.

Articles