CQRS (Query & Command Multiple Buses) | Symfony PHP
Как реализовать CQRS подход в Symfony приложении, используя шины команд и запросов (Query & Command Multiple Buses).
Telegram: t.me/alejandroyakovlev
Уроки, менторство - boosty.to/sashokgorshok
Как реализовать CQRS подход в Symfony приложении, используя шины команд и запросов (Query & Command Multiple Buses).
Telegram: t.me/alejandroyakovlev
Уроки, менторство - boosty.to/sashokgorshok
Пікірлер: 60
Уроки, менторство - boosty.to/sashokgorshok
Очень познавательный урок, как и все остальные на этом канале. Хотелось бы больше видео.
Круто! Спасибо большое за работу 🙂👍
Круто, продолжай!
Спасибо! Ты молодец!!!
Спасибо за видео. Я уже давно работаю программистом, но как-то не встречал данный термин и заинтересовало, решил посмотреть. Подход интересный, чем то напомнило GraphQL с его query и мутациями, в плане разделения запросов на чтение и запись или выполнение команд. Единственное (предыдущие видео не смотрел, может там было объяснение) для новичков наверно не особо понятен принцип создания такой структуры приложения, нужно бы про domain driven design рассказать. Еще есть вопрос - если в микросервисе подразумевается наличие только команд, то есть все запросы это обратись к api и дай мне ответ что все окей или обратись к api и кинь в очередь сообщение что все окей. Вот в таком случае есть смысл использовать данный паттерн? Или это избыточно?
Алехандро - уже 5 дней прошло - а вкусного видео до сих пор нет )))) Хотя в репо пару интересных вещей уже есть...... Ждемс
@AlejandroYakovlev
2 жыл бұрын
Записал, монтирую, в скором времени будет на канале! Спасибо за поддержку! ))
@maximsymfony
2 жыл бұрын
@@AlejandroYakovlev Если не секрет сколько лет, может и месяцев ты "шёл" к правильной архитектуре? Ты самоучка или хороший учитель был? Сколько у тебя лет опыта? P.s. Прости за то что тыкаю, просто мне кажется это более дружелюбно. Если ты против буду Выкать. Мне не сложно.
@AlejandroYakovlev
2 жыл бұрын
В моём случае хорошие учителя были те, которые показывали как делать не надо :) Главный вопрос здесь, полагаю, не "сколько времени", а "каким образом". Ведь один человек за месяц может освоить то, что другой изучает годами. Здесь важны и условия и стимул. Безусловно нужен хороший ментор, который на голову выше во многих вопросах, не только технических. И в роли ментора хорошо выступают не только тех лиды, но и книги, статьи и видеоматериалы. Чтобы развиться в архитектурном направлении нужная хорошая почва для практики и разносторонний технический бэкграунд. У меня опыт разработки на данный момент 7 лет. Но вопросами архитектуры я занимаюсь только последние 3 года.
Спасибо большое за видео, но не очень понятно как с данным подходом реализовать непосредственно запись в одно место, а чтение из другого при наличии чистой архитектуры. Т.е у нас есть интерфейс репозитория где мы вызываем методы для чтения и записи, и на уровне юз кейсов мы не мыслим понятиями куда конкретно запишется и от куда конкретно прочитается. И получается, что если мы хотим иметь отдельное представление для чтения, то мы уже внутри конкретной имплементации репозитория реализуем запись в одно место, а чтение из другого и непонятно чем тут помогает разбиение на разные шины, если разделение логики чтения/записи происходит в репозитории. Мы фактически можем сделать тоже самое и без шин и разделения сервисов на команды и запросы. Выглядит так, будто разбиение на разные шины нужны просто чтобы визуально разделить друг от друга команды и запросы и возможность регулировать синхронность/асинхронность в них
Ты бог!
@AlejandroYakovlev
Жыл бұрын
Все мы боги :)
Спасибо за видео. А что за приложение ты делаешь? Почему в браузере не показываешь? Мне очень интересно но не все понимают.
@AlejandroYakovlev
Ай бұрын
В этом уроке еще не было конкретной тематики приложения. Позже в телеграм канале общим голосованием (t.me/alejandroyakovlev/15) было решено делать приложение по оценке навыков сотрудников.
Очень круто, мне понравился подход CQRS в целом подход понятен и интересен. Вопрос с такими штуками как RabbitMQ и как это все использовать вместе и в каких случаях было бы очень интересно, особенно на примере микросервисного подхода, просто у меня не было опыта работы с сервисами очередей и вот то, что сделано в этом видео это по сути оно и есть?
@AlejandroYakovlev
Жыл бұрын
Это не совсем про очереди, но очень близко :) Будет отдельный ролик на тему очередей.
Привет)) Видео класс. Как с тобой можно связаться по Event Storming?
@AlejandroYakovlev
2 жыл бұрын
t.me/alex6ndr
а потом удивляются зачем Ларавел стал популярным из всех
Привет, Саша, хочу задать тебе вопрос - Telegram не находит тебя - как с тобой связаться?
@AlejandroYakovlev
Жыл бұрын
t.me/alex6ndr
1 - А почему ты в FindUserByEmailQueryHandler возращаешь UserDto, а не саму сущность User? 2 - И почему в конструктор CreateUserCommand не передать сразу готовую дто либо саму сущность? 3 - На каком уровне и где происходит логирование, допустим, такой пользователь уже существует UniqueConstraintViolationException, можно логировать в CreateUserCommandHandler?
@AlejandroYakovlev
2 жыл бұрын
1. DTO более гибкая, и может содержать более широкий перечень свойств и в совершенно инос представлении. Плюс приитаком подходе сущность будет более защищенной от случайных мутаций. 2. Можно DTO передать, это особенно полезно, когда параметры в избытке. 3. На прикладном слое.
Отличные видео. Но у меня вопрос - должен ли Command возвращать что-нибудь (тут возвращает) и почему в хендлер передается не "CommandInteface $command", а "CreateUserCommand" сразу
@AlejandroYakovlev
2 жыл бұрын
Command по сути является DTO. Её хэндлер может возвращать результат работы: исключения, список ошибок, id созданной сущности. CreateUserCommandHandler на вход принимает команду, как раз таки реализующую CommandInterface.
@hackhawk307
Жыл бұрын
@@AlejandroYakovlev когда команда возвращает ид созданной записи - это ломает суть асинхрнности cqrs. Правильнее было бы при создании юзера передавать заранее сгенерированный ид
Автор молодец, отличная демонстрация знаний работы месенджера, но считаю что тема совсем не раскрыта (и раскрыта не в тему). Нужен реальный пример из жизни, когда это стало бы необходимым. Плюс, CQRS как раз таки применяют для того, что бы доменный интерфейс репозитория не разбухал от методов вроде findByEmailAndRegisterDate() или findAllAndHereStarsOrderedByCreationDate($limit = 10)...
Damain? Шторм не ругался?
Если вы добавляете Пльзователю Profile , по какому полю вы их свяжите ulid int or ulid ulid? Хочу понять в User вы используете ulid из каких соображений, и вообще когда вы его используете? У ulid - есть минус, он не читаем человеком :) . Уроки хороши.
@AlejandroYakovlev
2 жыл бұрын
Главнное преимущество в стравнении с INT auto increment , генерируеммым на стороне БД - это заранее известное значение идентификатора до записи в БД, которое позваляет строить агрегаты, отношения, генерировать события предметной области и пр. Поюс ulid уникальный в глобальном масштабе, что не скажешь о int, часто уникальный в пределах таблицы. Отношения вяжутся по ulid.
@fitter2boss72
2 жыл бұрын
@@AlejandroYakovlev А для Profiler (продолжая вопрос User Profile , One To One) Вы бы создавали свой ulid или сразу бы создовали с тем же , что и User?
@AlejandroYakovlev
2 жыл бұрын
Однозначно свой ulid. Мухи отдельно, котлеты отдельно. Проще понимать структуру, когда идентификация сущности не зависит от внешних связей. Особенно если сущность со временем может превратиться в отдельный самостоятельный агрегат.
Почему null но не исключение? Какой профит даёт бесконечное поднятие null? Чем плохо кинуть эксепшен из репозитория, ведь на уровне репозитория это исключительная ситуация, т.к. метод обещает (по названию) вернуть пользоователя, но не может этого сделать (по неизвестной причине).
@AlejandroYakovlev
10 ай бұрын
Здесь вопрос удобства, места и времени. Попробуйте и так, и этак. В одном месте проще исключение кинуть, в другом null. В одном случае вам придется try catch обмазываться, в другом if. Где-то удобно контекст в исключении тащить, где-то в CommandResult. Вообще очень много нюансов. Действуйте по наитию.
Как CQRS реализовать Update в котором присутствует и чтение и запись?
@AlejandroYakovlev
11 ай бұрын
В виде команды.
Прежде всего скажу, что отличные уроки! А потом уже спрошу почему вы добавляете ключевое слово interface к интерфейсам, ведь это считается сейчас очень дурным тоном?
@AlejandroYakovlev
2 жыл бұрын
Благодарю за отзыв! :) Если Вы о венгерской нотации, то она как лакарство - в малых дозах полезно, в больших - яд. Я являюсь противником избыточной информации в нейминге, если язык предполагает типизацию. Преимущества в случае с суффиксом Interface: 1. В Symfony так принято, если посмотреть на документацию. 2. Autocomplete в IDE при вводе Interface при создании класса через конструктор - лайфак, ускоряющий жизнь на несколько секунд. 3. Наглядность и определенность - мы явно видим, что внедряется интерфейс. Пробовал: Foo - интерфейс FooBarImpl - реализация. Тоже неплохо. В общем, как договоритесь в команде, так и делайте. Дело вкуса и удобства :)
@Zlobusz
Жыл бұрын
Где это считается "очень дурным тоном"? Где-то считается, а где-то нет. Вопрос весьма спорный. Мне например норм сразу видеть, что это интерфейс (с суфиксом), кто-то любит в стиле C# обзывать с заглавной латинской i (например IUserRepository). Это чисто вкусовщина. Ой не туда вы замечания делаете, совсем не туда....
всё очень классно, но очень тихо
Спасибо, клёво. Вопрос 1) зачем нужны ДТО-шки. 2) Зачем так заморачиваться с папками Сущности в проекте? В другое место класть, в чем профит? 3) Смысл CQRS поняен, но то что ты сделал в Симфонии - реализация не очень.... 4) Ссылки пожалуйста добавь на Мартина Фаулера
@fitter2boss72
2 жыл бұрын
А вы не все видео посмотрели? Вроде в видео о архитектуре поясняется.
@maksimsalekseicevs3987
2 жыл бұрын
@@fitter2boss72 честно, начал с конца как носподин Ютуб пожелал, дошёл до начала, и все равно это все мутно. Мы можем придумать вместо мопеда мотоцикл, он поедет быстрее, но архитектура все равно мопеда, просто рама потолще, да мотор с тормозами помощнее, в целом все тоже "колесо"
@fitter2boss72
2 жыл бұрын
@@maksimsalekseicevs3987 Для домашнего проекта эта архитектура оверхэд, но для сложных, где вам может быть понадобиться маштабируемость и микросервисы там это зайдет. Уже одно то, что бизнес логика может быть просто скопирована на другой фреймворк дорогого стоит. И еще добавлю, видео о домашних проектах "без" архитектуры (или с простой архитектурой) дофига, а о "взрослых" кот наплакал, я даже не вспомню никого, разве Дмитрия Е.
@AlejandroYakovlev
2 жыл бұрын
1. DTO - для передачи данных, не более. 2. Сущности имеют прямое отношение к предметной области и находятся на слое, где эта предметная область представлена. 3. Опиши более конструктивно, что ты имеешь ввиду с примером альтернативной реализации. 4. Ссылки указаны в видео.
@maksimsalekseicevs3987
2 жыл бұрын
@@fitter2boss72 все живут сегодняшним днем, тяп ляп и в продакшЭн. Платят же за то что работает, а не за правильную архитектуру )) я не приверженец RAD, просто если вокруг посмотреть, так и есть. Тем более я считаю Симфонию Enterprise Framework. Спасибо за разеснение, пожалуй копи пайсте папки в другой фрейм самый везкий аргумент.
А где юзкейзы? В чистой архитектуре они должны быть. Плюс в чистой архитектуре существует не гласное правило хорошего тона - метод, либо ничего не возвращает, либо должен вернуть ошибку, либо должен вернуть сущность. Это значит, что метод не должен возвращать null. И не важно, относиться этот метод к репозиторию, или к адаптеру, или же к сервису юзкейза. А отсюда соответственно следует, что ошибки бизнес логики - это ошибки, а не исключительные ситуации. То есть метод может вернуть либо ошибку, либо полезность, чаще всего сущность. В других языках для этого есть монады result или either, или есть возможность вернуть кортеж вида {result(:ok/:error), some_value}.
Почему-то в начале кажется, что гемороя с этими тестами больше чем от того с чем они призваны справляться :(
Видео интересное. Но считаю, что интерфейс для репозитория не нужен
@Zlobusz
Жыл бұрын
Еще раз прочитай про гексогональную архитектуру портов и адаптеров. Application Layer должен основываться на интерфейсах Domain Layer, а Infrastructure Layer хранит в себе реализации интерфейсов из Domain Layer. Попробуй вначале построить логику своего приложения исключительно на доктриновском репозитории и магических findBySomething, либо findBy(Criteria) или em->persist() em->flush(), а потом заменить DoctrineUserRepository на какой нить TarantolUserRepository, посмотрю я на тебя...
Всё круто, но о PSR при форматировании лучше не забывать. 😅
Видео хорошее, но для новичков можно было бы объяснить CQRS без излишеств, а тут все зачем-то усложнено в 10 раз, и много лишнего. Вообще можно было все в три файла уместить.
@AlejandroYakovlev
5 ай бұрын
Расскажите, пожалуйста, какие моменты считаете излишествами?
Нужно еще настроить БД для CQRS, чтобы запросы шли на слэйв, а комманды на мастер.
Удобство разработки?) Норм шутка)
Симфони отстой для недалёких.
@AlejandroYakovlev
Жыл бұрын
Добро пожаловать