службу приходит валидное DTO, мы собираемся создать какую-то сущность. Сущность в коструктор требует VO.
Для создание VO нам требуется выполнить ряд операций:
- бесплатные по времени: строка должна быть email, либо сравнение с какими-либо константами и т.д.
- Малозатратная по ресурсам: какой-нибудь запрос в базу, например на уникальность email
- Сильно затратная по ресурсам: VO в конструкторе требует данные из какого-то АПИ
Итого у нас есть сущность, у насть есть DTO с данными (контракт данных соблюден), у нас есть n VO из которых мы хотим собрать нашу сущность, но так же мы не хотим при этом затрачивать много времени/ресурсов.
Как сделать так, чтобы сначала были провалидированы бесплатные правила, потом малозатратные, потом сильно затратные
Уместно ли делать в таком случае сложный билдер, который будет полностью контролировать процесс создания сущности?
Например вначале инвокать все бесплатные проверки, затем малозатратные проверки, затем сильно затратные, затем собирать VO и совать их в сущность?
При этом подходе (с приоритизацией) появляются проблемы т.к. VO больше не отвечает за свою валидность в момент создания.
Например:
1. валидируем уникальность email до создания VO (потому что не хотим вызывать АПИ если email не уникален, при этом данные из АПИ нужны при создании VO)
2. в стат конструкторе VO мы все равно должны проверить email на уникальность, т.к. конструктор могут инвокнуть откуда угодно
^ Это тоже можно решить за счет создания определенных приватных полей-флагов в рамках самой VO. Мол если валидация такого-то поля была инвокнута уже, то повторно валидировать его не надо, либо хранить как-то в кеше
Ваши мыли по этому поводу @dexplon @fes0r
создавай ВО в том порядке, в каком хочешь валидировать =)
в VO есть конструктор, конструктор требует в себя данные в т.ч. данные из АПИ. Мы не хотим запрашивать данные из АПИ, если провалится валидация уникальности email И мы не хотим искать email в базе до того, как не убедимся, что это действительно email
Чет читал читал, и не понял проблемы. Логично делать сначала легкие операции. Плюс нужно смотреть по месту, на сколько какой кейс более частый или нет. Не старайтесь найти золотую кнопку. Есть множество решений, они все будут рабочими. А для бизнеса главное рабочие решения. Для архитектуры же важно чтобы можно было легко расширяться, легко читался код, легко тестировалось и при этом не оверхэдить лишний раз. Если разные методы под это все подходят - они все хороши.
2. в стат конструкторе VO мы все равно должны проверить email на уникальность, т.к. конструктор могут инвокнуть откуда угодно Вот это вообще мало понятно. Почему VO должно быть проверено на уникальность в рамках логики VO
фабрики, которые берут на себя начало жизненного цикла для сущностей или DTO, пересмотр что есть валидация данных а что инварианты (например тот факт что у тебя email должен быть валиден - валидация ДО сохранения тут бесполезна - тут надо ловить фэйлы констрейнтов в базе уже после сохранения). Есть такое достаточно простое правило - конструкторам не желательно кидать исключения. Потому тебе нужны фабрики и билдеры. Причем другие сущности вполне могут быть этими фабриками или билдерами. Не надо зацикливаться что фабрика это "сервис с суфиксом Factory"
А почему конструкторы не должны исключения кидать? Как тогда быть уверенным в валидности сущности/VO?
на счет fail constrain, суть в том, чтобы проверить сначала малозатратные правила, например уникальность email, а поотом если оно валидно - дерагать какие-то затратные АПИ, например платные АПИ или ресурсоемкие запросы
что бы флоу данных более явный был, что бы меньше сайд эффектов. Есть много кейсов когда "что валидно а что нет" решает юзкейс по которому ты что-то создаешь. Перетаскивание этой логики в сущность обычно делает все существенно сложнее. Сущность должна тебе гарантировать что дернув ее метод (а конструктор это ДО этого) изменения стэйта будут консистентны, но за начало жизненного цикла может отвечать кто-то другой
прикинь насколько это вероятный сценарий. Если ты таким образом отсекаешь 1-2% запросов то в этой "оптимизации" нет никакого смысла
Понятно, спасибо за развернутый ответ :)
твои ответы заставляют много думать, благодарю)
Тоесть defensive принцип который говорит что сущность не может существовать в невалидном состоянии идет нафиг?
Почему же? Нет, просто конструктор это такая штука что объекта у тебя как такового ещё и нет
Ну результатом работы конструктора, небросающего исключение, будет обьект в невалидном состоянии (с точки зрения бизнес-правил)
нет если у тебя за это отвечает фабрика)
А кто мешает создать мимо фабрики?
ревью. статик анализ
+ мы должны спроектировать обьект так, чтобы его нельзя было создать невалидным
нет, мы должны мозги включать и анализировать риски
В пхп такого нет. Но псалмом же можно сделать что то типа видимости на уровне пакета?
Ок, а в чем соственно плюс фабрик перед статик конструктором этого же объекта? Понятно что чуть больше отвественности, но это только на словах. Не нужно полагаться на доп средства (анализ и ревью) - и защищенный конструктор.
Ну в стат анализ много что дополнительного вшивают, видимо и такое можно.
ну вот будет у тебя сущность с 6-ю статическими фабриками - обсудим)
ну 6 стат конструкторов это такое себе, рыли
ты можешь комбинировать, фабрика дергает статическую файбрику которрая жестко фиксирует структуры... но.... это перебор обычно
Ну 6 конструкторов - это это 6 кейсов, что уже возможно странно для обычного использования агрегата, который опять таки должен по хорошему быть маленьким из-за высокой декомпозиции. Т.е. это скорее редкий кейс чем регулярный
ну и да - статический конструктор это те же фабрики. я активно их юзаю, но в целом для сущностей есть еще правило "Don't create aggregate roots".
Для этого правила наверное нужно сначало хорошо всё подробить и избавиться от примитивов.
по сути это все к вопросу как и откуда у тебя данные появляются и ходят. Так что это скорее способ это сделать.
Это же касается примитивов. Если у людей данные ходят в примитивах до момента создания агрегата, то не получится.
> например тот факт что у тебя email должен быть валиден - валидация ДО сохранения тут бесполезна Имелось ввиду уникальный?
ну логично что не получится) это вообще уже чуть дальше вопросы. Опять же - Whole Value и прочее.... это сложно и этому надо учиться.
Обсуждают сегодня