Для тех кто не понял, это делается так.
Я согласен, что можно упаковать UUID в Bse64, но мне кажется проще сразу сгенерировать Base64.
Да и не всегда нужен такой длинный id.
YouTube же как-то обходится 11 символами.
Спасибо. Довольно занятная штука.
Я смотрю разные реализации и вижу что вместо generator используют datacenter ID и machine ID.
Я не нашел примера с generator. Что это должно быть? Случайно генерируемое число?
Окей. Вы подмешиваете данных в возвращаемое значение. Тоже метод решения задачи. С таким же успехом можно использовать аргумент out (возвращаемся к разделу ICommandHandler должен всегда возвращать void?).
Можно придумать еще с 10 костылей, но зачем?
Это тоже самое, что ValidatorMiddleware. И middleware на мой взгляд предпочтительней декораторов.
Но сути это не меняет. Нужно бросить исключение чтоб прекратить выполнение и поднять сообщение(я) об ошибке наверх в контроллер. Я не в восторге от такого подхода.
Во первых, мы должны на уровне интерфейса ограничить возможность выполнить платеж на сумму превышающую остаток по счету.
Во вторых, да. Нам нужно проверить остаток по счету прежде чем мы отправим запрос дальше по стеку. Это не нужно делать прямым обращением к репозиторию. Это можно сделать через валидаторы и спецификации.
В ином же случае нам придется валидацию размазывать по коду и бросать исключения в сервисах и моделях, а исключение это само по себе плохо и использовать их для передачи данных в верх по стеку крайне не желательны.
Однако, это не отменяет необходимости валидировать данные на доменном слое. Причем валидирование как бизнес правил, так и самих данных. Об этом говорил Вернон. Я не приверженец двойной валидации, но это правильней. И тут каждый выбирает свою истину. Кто-то размазывать валидацию, кто-то концентрирует валидацию в контроллерах, а кто-то использует двойную валидацию.
В целом, я согласен, что уровней валидации несколько, но вся валидация все равно должна выполняться в контроллере, а на слой бизнес логики должны приходить уже валидные данные.
А вот если на слой бизнес логики придут невалидные данные, то это уже будет исключением.
Единственное, что мне до сей поры очень плохо ясно, это куда во всей этой схеме пихать валидацию?
Валидацию нужно пихать туда, где вы будете обрабатывать ошибки и отдавать клиенту, то есть в контроллер.
Валидировать команды в command heandlers или middleware не правильно, так как вы не сможете корректно отреагировать на обнаруженные ошибки.
Да, вы можете сделать валидирующий middleware и бросать ValidationExcepton, но это неверно с точки зрения семантики, так как невалидные данные не являются исключительной ситуацией.
Ну во первых, совершенно очевидно, что неопытный разработчик может трактовать это неправильно и начать писать SQL запросы в HTML шаблонах, от чего я и хочу предостеречь.
Опытный же разработчик понимает, что такое архитектурные шаблоны, как они работают, какие у них есть преимущества, недостатки и применяет тот или иной подход исходя из задачи, а не исходя из моды, хайпа и личных предпочтений. И для опытного разработчика не нужна ни эта статья ни мои комментарии.
Тут наверное стоит упомянуть о CQRS, который вы видимо подразумевали.
Да, в CQRS мы разделяем read и write потоки, но во первых это делается с целью оптимизации нагрузки и новички обычно этим не занимаются, а во вторых, все описанные архитектурные шаблоны (Слои, Луковицы, Гексогоны, Порты и Адаптеры) относятся к write потоку. То есть CQRS это скорей надстройка над архитектурой чем замена.
Исходя из этого я и хочу сделать акцент на том, что write поток в Data Access из UI в обход Domain должен быть ограничен, а read поток может идти в обход, но это уже совсем другая история.
И конечно, из любого правила бывают исключения. Бывает, что во write потоке, архитектура со всеми своими наворотами, просто не справляется с нагрузкой и тогда создают отдельный Front controller который без всяких фраймворков и прочего, тупо фигачит данные в хранилище (по сути микросервис).
Обычно я так и делаю. Один пакет чистый без зависимостей, а второй bundle для Symfony с конфигами и всеми делами.
Хочешь юзать в Symfony ставь бандл. Если у тебя не Symfony, юзай чистый пакет.
Я сейчас перевожу один проект на PHP 7. Одн из пакетов оказался не совместим с PHP 7.
Так как проект заброшен, я просто взял и заменил его на другой. Переписал пару адаптеров и все.
Ну ещё немножко смазал маслицем чтоб лучше зашёл
Очевидно же, что в библиотеке require желательно оставить пустым, а в require-dev пишем, что хотим, так как эти пакеты используются только для разработки и тестирования и к клиенту они не попадут.
В проекте же, в require, можно вообще любые зависимости держать. За них отвечает команда разработчиков.
Проблема совмещения не совместимых пакетов мне вообще не понятна.
Зачем пытаться совместить несовместимое?
Если пакеты не совместимы, то просто не используйте их или выберете совместимую версию. В крайнем случае, всегда можно выбрать конкретный коммит в пакете. Да, выбрать конкретную версию зависимости у зависимости тоже можно.
А если хочется использовать фичу из последней версии пакета, которая не совместима с другими пакетами, то просто не используйте эту фичу. Подождите пока исправят совместить или сделайте PR.
Не стоит гнаться за последними релизами.
Мне бывает приходится использовать фиксированную версию пакетов, но только потому, что разработки ломают обратную совместимость.
Решение vendor in vendor мне видится странным и наверняка добавит проблем.
JS это штатные средства, а решение кросбраузерное и всего в несколько строк кода.
В любом случае нужно на чем-то описать бизнес логику, а js, кроме всего прочего, позволяет проверить не заблокирована ли ссылка на которую будем делать редирект.
Ну почему же нельзя куки передавать. Можно. Ходы надо знать.
Думаете как SSO работает?
Просто придется переадресацию делать через js, а не через nginx.
А по хорошему куку передавать и не надо.
Один раз переадресовали и поставили куку на домен.
Если куки нет то запускаем ещё раз процедуру переадресацией.
Если добавить к этому несколько доменов второго уровня, то получится неплохая защита для распространения нелегального контента.
Собственно вирусы так и распространяются.
Ну почему же? Я упомянул в статье хеширующие библиотеки.
Кроме hashids полно других аналогичных библиотек.
В этой статье речь не о них.
Для тех кто не понял, это делается так.
Я согласен, что можно упаковать UUID в Bse64, но мне кажется проще сразу сгенерировать Base64.
Да и не всегда нужен такой длинный id.
YouTube же как-то обходится 11 символами.
Спасибо. Исправил
Действительно. Обсчитался. Прошу прощения
Спасибо. Довольно занятная штука.
Я смотрю разные реализации и вижу что вместо generator используют datacenter ID и machine ID.
Я не нашел примера с generator. Что это должно быть? Случайно генерируемое число?
Скажите, через что вы смотрите статью?
В статье написано (2341):
Много таких кому некорректно выводится возведение в степень?
Это только пример. Вам ни кто не мешает заменить метод генерации уникального значения.
только потому, что это удобней в расчетах 64 = 26
Окей. Вы подмешиваете данных в возвращаемое значение. Тоже метод решения задачи. С таким же успехом можно использовать аргумент out (возвращаемся к разделу ICommandHandler должен всегда возвращать void?).
Можно придумать еще с 10 костылей, но зачем?
Это тоже самое, что ValidatorMiddleware. И middleware на мой взгляд предпочтительней декораторов.
Но сути это не меняет. Нужно бросить исключение чтоб прекратить выполнение и поднять сообщение(я) об ошибке наверх в контроллер. Я не в восторге от такого подхода.
Во первых, мы должны на уровне интерфейса ограничить возможность выполнить платеж на сумму превышающую остаток по счету.
Во вторых, да. Нам нужно проверить остаток по счету прежде чем мы отправим запрос дальше по стеку. Это не нужно делать прямым обращением к репозиторию. Это можно сделать через валидаторы и спецификации.
В ином же случае нам придется валидацию размазывать по коду и бросать исключения в сервисах и моделях, а исключение это само по себе плохо и использовать их для передачи данных в верх по стеку крайне не желательны.
Однако, это не отменяет необходимости валидировать данные на доменном слое. Причем валидирование как бизнес правил, так и самих данных. Об этом говорил Вернон. Я не приверженец двойной валидации, но это правильней. И тут каждый выбирает свою истину. Кто-то размазывать валидацию, кто-то концентрирует валидацию в контроллерах, а кто-то использует двойную валидацию.
В целом, я согласен, что уровней валидации несколько, но вся валидация все равно должна выполняться в контроллере, а на слой бизнес логики должны приходить уже валидные данные.
А вот если на слой бизнес логики придут невалидные данные, то это уже будет исключением.
Валидацию нужно пихать туда, где вы будете обрабатывать ошибки и отдавать клиенту, то есть в контроллер.
Валидировать команды в command heandlers или middleware не правильно, так как вы не сможете корректно отреагировать на обнаруженные ошибки.
Да, вы можете сделать валидирующий middleware и бросать
ValidationExcepton, но это неверно с точки зрения семантики, так как невалидные данные не являются исключительной ситуацией.Рекомендую посмотреть готовые библиотеки реализующие CQRS, Middleware, Payload.
Ну во первых, совершенно очевидно, что неопытный разработчик может трактовать это неправильно и начать писать SQL запросы в HTML шаблонах, от чего я и хочу предостеречь.
Опытный же разработчик понимает, что такое архитектурные шаблоны, как они работают, какие у них есть преимущества, недостатки и применяет тот или иной подход исходя из задачи, а не исходя из моды, хайпа и личных предпочтений. И для опытного разработчика не нужна ни эта статья ни мои комментарии.
Тут наверное стоит упомянуть о CQRS, который вы видимо подразумевали.
Да, в CQRS мы разделяем read и write потоки, но во первых это делается с целью оптимизации нагрузки и новички обычно этим не занимаются, а во вторых, все описанные архитектурные шаблоны (Слои, Луковицы, Гексогоны, Порты и Адаптеры) относятся к write потоку. То есть CQRS это скорей надстройка над архитектурой чем замена.
Исходя из этого я и хочу сделать акцент на том, что write поток в Data Access из UI в обход Domain должен быть ограничен, а read поток может идти в обход, но это уже совсем другая история.
И конечно, из любого правила бывают исключения. Бывает, что во write потоке, архитектура со всеми своими наворотами, просто не справляется с нагрузкой и тогда создают отдельный Front controller который без всяких фраймворков и прочего, тупо фигачит данные в хранилище (по сути микросервис).
Обычно я так и делаю. Один пакет чистый без зависимостей, а второй bundle для Symfony с конфигами и всеми делами.
Хочешь юзать в Symfony ставь бандл. Если у тебя не Symfony, юзай чистый пакет.
Я сейчас перевожу один проект на PHP 7. Одн из пакетов оказался не совместим с PHP 7.
Так как проект заброшен, я просто взял и заменил его на другой. Переписал пару адаптеров и все.
Ну ещё немножко смазал маслицем чтоб лучше зашёл
Я видимо что-то не понимаю.
Очевидно же, что в библиотеке
requireжелательно оставить пустым, а вrequire-devпишем, что хотим, так как эти пакеты используются только для разработки и тестирования и к клиенту они не попадут.В проекте же, в
require, можно вообще любые зависимости держать. За них отвечает команда разработчиков.Проблема совмещения не совместимых пакетов мне вообще не понятна.
Зачем пытаться совместить несовместимое?
Если пакеты не совместимы, то просто не используйте их или выберете совместимую версию. В крайнем случае, всегда можно выбрать конкретный коммит в пакете. Да, выбрать конкретную версию зависимости у зависимости тоже можно.
А если хочется использовать фичу из последней версии пакета, которая не совместима с другими пакетами, то просто не используйте эту фичу. Подождите пока исправят совместить или сделайте PR.
Не стоит гнаться за последними релизами.
Мне бывает приходится использовать фиксированную версию пакетов, но только потому, что разработки ломают обратную совместимость.
Решение vendor in vendor мне видится странным и наверняка добавит проблем.
JS это штатные средства, а решение кросбраузерное и всего в несколько строк кода.
В любом случае нужно на чем-то описать бизнес логику, а js, кроме всего прочего, позволяет проверить не заблокирована ли ссылка на которую будем делать редирект.
PS: блокировать ссылки могут ещё антивирусы
Ну почему же нельзя куки передавать. Можно. Ходы надо знать.
Думаете как SSO работает?
Просто придется переадресацию делать через js, а не через nginx.
А по хорошему куку передавать и не надо.
Один раз переадресовали и поставили куку на домен.
Если куки нет то запускаем ещё раз процедуру переадресацией.
Если добавить к этому несколько доменов второго уровня, то получится неплохая защита для распространения нелегального контента.
Собственно вирусы так и распространяются.