метод без side effects, которому нужно возвращать результат

fixxxer

К.О.
Партнер клуба
в модель они поставляют правильные данные
Если вот так разделять, что валидация формы не лезет в базу, то это уневозможит очень нужный кейс - показать пользователю как можно много ошибок для исправления.
у тебя в голове yii
Показать можно что угодно, если с точки зрения UI уместно сделать предварительную проверку - ну пусть она делается. В реалиях 2018 года такие проверки делаются еще в ходе заполнения формы Javascript-ом, так что тут вообще будет отдельный api-метод. Даже если и не так, необходимость обработки исключения это все равно не отменяет.

"Поставляет в модель данные" - это вообще жесть. :) Как только ты начнешь относиться к модели не как к аналогу структуры в Си/Паскале, а к полноценному объекту с инкапсуляцией и реализацией бизнес-логики, многие вещи станут выглядеть иначе, и многие фичи rails-подобных фреймворков типа yii/laravel окажутся бесполезными, или, как минимум, требующими пересмотра способа их использования.

Еще, хотя это уже несколько не по теме, отмечу, что интерфейсы вида "большая форма, напрямую соответствующая полям в базе данных", как правило, не самые удобные и понятные. Они исторически сложились 15 лет назад, когда Javascript был примитивен, не было никаких XMLHttpRequest, и типичным способом доступа в интернет был модемный диалап. В десктопных приложениях мы и в те времена гораздо чаще видели интерфейс, основанный на командах, чем на формах, на десктопе термин MVC понимался куда более однозначно, а в вебе исказился до такой неузнаваемости, что вообще потерял смысл. Так что, анемичные модели - это во многом тяжелое наследие ограничений раннего веба.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Но как в общем случае проверить что данные корректные, email не занят в т.ч., без базы?
На какой-то конференции Greg Young рассказывал, что его просто затрахали вопросом уникальности email'а.
Да не имеет значения как ты это сделаешь, сделай UNIQUE поле на email, это не то, на чём нужно сосредоточиться.
Сама по себе уникальность email'а к модели пользователя не имеет никакого отношения.
Гораздо важнее: команды, события, вытекающие из них aggregate roots и bounded contexts.
Нужно делать акцент на глаголы (команды/события), а не на свойства.

В случае же event sourcing'а не грешно сделать лок, в котором ты сгоняешь в read model за актуальными email'ами для проверки уникальности прямо в command handler.
 

Вурдалак

Продвинутый новичок
@ivanov77, я, как любитель проводить неуместные аналогии, могу сказать, что ты примерно рассуждаешь так: вот есть игра «Шахматы». Вот у неё есть правила, команды (двинуть фигуру, сделать рокировку и т.д.), а ты пытаешься сделать так, чтобы aggregate root Game проверял уникальность игроков глобально (чтобы один и тот же игрок не участвовал в двух чемпионатах одновременно, в одну и ту же минуту).

Так вот самой игре «Шахматы» на подобные вопросы наплевать. Наша модель выполняет ровно ту задачу, которая перед ней стоит (определяет победителя после последовательности действий со стороны игроков согласно шахматным правилам).

Также очевидно, что модель Шахматы не должна позволять выполнять действия, явно противоречащие правилам игры (попытаться двинуть фигуру коня по диагонали как слона – это будет исключение, до которого никогда не должно доходить). Но одновременно же с этим, подобная бессмыслица должна быть запрещена еще и на уровне UI.

Единственное, что в этом примере может показаться неудачным — это то, что «Шахматы», де-факто, generic domain, правила одинаковые и дублирование в нескольких местах ни у кого вопросов не возникает.

Дублирование становится проблемой тогда тогда, когда ты дублируешь некое знание в пределах одного bounded context.
А «Шахматы» (чистая модель) и «Шахматы UI на Angular.js» — это 2 разных bounded context'а.
В определении DRY под расплывчатым словом «system» понимается именно bounded context:

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system bounded context.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Даже если и не так, необходимость обработки исключения это все равно не отменяет.
Спорный момент.
То есть, как бы да, но...

Если для тебя это актуально, command bus по факту работает только с unchecked-исключениями.
Можно добавить generic checked-исключения типа AggregateAlreadyExists, AggregateWasNotFound. Но это дерьмовый подход. Нередко у меня «UPSERT» логика, AggregateAlreadyExists никогда не вылетит, а обработать должен (если не игнорировать PhpStorm).

Можно добавить какой-то Response с ошибками, событиями. Но контракт будет неявный, через массивы.

Тут можно несколько упростить, если сделать несколько методов для command bus, которые ведут себя по-разному.
Иногда мне реально наплевать, fire-and-forget, есть будут исключения — это unchecked, они просто залоггируются.
Иногда хочется полного контроля, тут я бы хотел какой-то Response-объект (события + возможные ошибки общего плана [хотя необязательно]).
 

fixxxer

К.О.
Партнер клуба
Я признаюсь в страшном: я допускаю возможность, что commandBus.execute() возвращает response object :)

По-хорошему, наверное, надо два разных метода. У меня таких случаев слишком мало для того, чтобы все обросло дикими if-ами, но предпосылки оно создает, ага.

Вообще надо как-нибудь осилить полноценный event sourcing, есть подозрение, что многое упростится.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Ну вот я к двум методам и пришёл. Сам по себе command bus может возвращать response и ничего тут противоречащего паттерну нет. Главное, чтобы он не возвращал read models. А events и тем более exceptions (в response, ага)/errors — это по сути просто признак «успех/не успех», просто в другом виде.
 

Вурдалак

Продвинутый новичок
Хотя, проблема что сразу по первому несоответствию кинет, остальные проигнорирует.
Надеюсь, мы тут пришли к пониманию, что assertion'ы не должны использоваться для клиентской валидации. Падение assertion'а — это баг, до этого не должно доходить.

Но вообще есть т.н. lazy assertions: https://github.com/beberlei/assert#lazy-assertions
Но это исключительно для удобства разработчика, который будет смотреть в логи.
Это нельзя использовать для web-форм.
 

WMix

герр M:)ller
Партнер клуба
я с assertion не понимаю следующее, в вики и в других источниках предлагается отключать для скорости assertion в продуктивном модусе, что это часть разработки а не часть аппликации. и в этот момент я не вижу смысла в этом.
те object возможно будет "abnormal" и это ок.
Most languages allow assertions to be enabled or disabled globally, and sometimes independently. Assertions are often enabled during development and disabled during final testing and on release to the customer. Not checking assertions avoids the cost of evaluating the assertions while (assuming the assertions are free of side effects) still producing the same result under normal conditions. Under abnormal conditions, disabling assertion checking can mean that a program that would have aborted will continue to run. This is sometimes preferable.
https://en.wikipedia.org/wiki/Design_by_contract
Contract conditions should never be violated during execution of a bug-free program. Contracts are therefore typically only checked in debug mode during software development. Later at release, the contract checks are disabled to maximize performance.
 

WMix

герр M:)ller
Партнер клуба
шутишь или серьезно? у тебя включены или ловим исключение в другом месте.
 

fixxxer

К.О.
Партнер клуба
А, тебя смущает то, что библиотека называется assert?

Эта библиотека - просто короткий и удобный способ записать if (!condition) throw exception с рядом предопределенных conditions. Не нравится - пиши ручками if (!condition) throw exception, какая разница.

Никакого отношения к сишному макросу assert(3) она не имеет.
 

WMix

герр M:)ller
Партнер клуба
просто короткий и удобный способ записать if (!condition) throw exception
http://php.net/manual/ru/function.assert.php

намекаешь что https://github.com/beberlei/assert нечто другое чем http://php.net/manual/ru/function.assert.php или что http://man7.org/linux/man-pages/man3/assert.3.html никакого отношения к http://php.net/manual/ru/function.assert.php не имеет? или в википедии про другие assert/ы речь?
 

WMix

герр M:)ller
Партнер клуба
PHP:
assert($a !== null) // такого в проде нет
Assert::notNull($a) // нормально
 
Сверху