Как стать автором
Обновить

Комментарии 29

Это не статья, при всем уважении. Более того, я даже не смог императив уловить этого текста. Ну давайте расписывать оверусложненную архитектуру всяких hello-world-ов.

Императив очень простой - задача валидации, которая рассматривается в статье, решается внутри слоя logic layer.

а зачем, если нам нужен уникальный индекс по email в бд и обработка ошибки?

Зачем всё усложнять?

Поддерживаю @breninsul - без проверки уникальности на стороне БД будет шляпа так как параллельные запросы на создание могут оба увидеть что такого значения ещё нет в БД и оба перейти к этапу записи - уникальность на уровне БД обеспечивается средствами БД.

Конечно надо сделать уникальный индекс по полю с email в таблице базы данных. Но это не значит что не надо валидировать со стороны приложения. Валидация бизнес-данных - это элемент бизнес-логики приложения.

2жды пробрасывать ошибку? Или разные?

зачем?

Ошибка конечно одна и та же. Мой подход такой:

1) валидатор проверяет уникальность email по таблице базы данных; если email не уникален - генерируется ошибка;

2) если два пользователя одновременно создают записи с одинаковым email и валидация у них проходит правильно, то уже при сохранении в бд первый по времени сохранения пользователь завершает операцию сохранения данных в бд, а тот кто завершает транзакцию следующим по времени получает ошибку, которую генерирует индекс, следящий за уникальностью значения email в поле таблицы бд.

И в итоге если убрать валидатор, то ничего не измениться с точки зрения клиента, только будет на один запрос к БД меньше и в принципе кода меньше.
А в чём профит от того что валидатор на уникальный email есть?

Кроме проверки уникальности по базе данных валидатор также проверяет соответствует ли написание email формату, принятому для почтовых адресов. Возможно дополнительные ограничения - например почтовый домен только из ограниченного набора доменов и т.д.

Валидатор на уникальность - должен проверять только на уникальность.

Валидация формата - задача отдельного валидатора, который никак не связан с уникальностью.

Ну вот у нас атомарные валидаторы. А потом они всё равно где-то встречаются. Или атрибурами на модели, или в правилах валидации FluentValidator, например.

Так что я бы поспорил про "никак не связаны", у этих валидаторов временная связность в контексте проверки конкретной ДТОхи.

А ещё тут спор о терминах, т.к. валидатор во FluentValidator проверяет всю ДТОху, а проверка уникальности и т.п. - это правила валидации.

Кода не особо меньше будет, т.к. исключение нужно поймать и перевести в доступный пользователю формат. Особенно прикольно, если это форма на которой десяток полей и уникальность емейла - только одна из ошибок валидации.

А ещё нам нужно уметь отличать ошибки валидации от ошибок, требующих решения. Отличать одно от другого по исключениям летящим из БД непростая задача.

Всё описанное будет в любом случае так как ошибка уникальности на стороне БД всё равно вероятна и её всё равно нужно конвертировать в сообщение идентичное сообщению от валидатора (это не моё желание - так описал задачу ТС).

А вот кода валидатора на уникальность - не будет.
Как и тестов к нему.

 её всё равно нужно конвертировать в сообщение идентичное сообщению от валидатора

Если так, то согласен.

Но этого можно не делать и считать любую ошибку от БД необработанным исключением. Тогда всё становится просто: валидатор - валидирует, а БД бьёт по рукам, если программист ошибся.

Ну если обсуждаеть совершенно не то что изначально постулировалось ТС, то конечно можно получить другой вывод :)

Тогда всё становится просто: валидатор - валидирует, а БД бьёт по рукам, если программист ошибся.

Можно и так, то вот по рукам будут бить клиентов - пришёл создать пользователя, а получил невнятную ошибку от БД.

Да, есть такие риски. Говорит о плохом тестировании.

Зато алертинг сразу возбудился и поддержка отработала.

а тот кто завершает транзакцию следующим по времени получает ошибку, которую генерирует индекс, следящий за уникальностью значения email в поле таблицы бд.

Про ТС не совсем понял. Если речь про это, то я считаю, что здесь будет ошибка, а не ошибка валидации.

ТС это "топик стартер" = то есть тот с кого началось обсуждение в ветке.
И от него была постановка что ошибка и на уровне валидатора и на уровне БД должны для клиента выглядить одинаково:

Ошибка конечно одна и та же.

Если на это требование забить, то тогда конвертировать ошибку ограничения уникальности со стороны БД уже будет не нужно и тогда да, нужен отдельный валидатор чтобы показывать клиенту внятное сообщение вместо не внятной ошибки БД.
Но в рамках этой ветки обсуждается концепция того что и даже в случае ошибки уже на уровне БД, клиент бы всё равно увидел ответ такой же как если бы отработал просто валидатор.

В том то прикол, что написано про ошибку и можно интерпретировать по разному. Я понял как просто ошибку, но видимо имелась ввиду ошибка валидации. О чём я написал в верхнем комментарии, даже с цитатой спорного места.

А чем этот вариант отличается от

Вариант 3: «Короче, просто провалидируем это в самом юзкейсе приложения перед созданием пользователя»

Апликейшен сервис по сути юскейс. Дергаем валидатор, создаём пользователя, вставляем в бд. То же самое же.

Валидатора как такового нет. Напрямую идёт обращение к репозиторию usersRepository.GetByEmail(email)

На мой взгляд валидатор надо выделить в отдельный объект и далее его можно многократно использовать внутри logic layer.

А если GetByEmail что-то вернул, то возвращаем ошибку. Валидация же! Хоть не в отдельном блоке.

В данном случае без разницы, код будет прямо в юскейсе или вынесен отдельный валидатор. В любом случае в logic layer или в юскейсе будет что-то типа if(какое-то условие) return ошибка валидации; . И вся исходная статья о том, как бы этот иф не забыть в будущем.

Очень хорошо сказано в комментарии https://habr.com/ru/articles/797425/#comment_26597341 - "ответственность репозитория должна быть ограничена сохранением и получением данных из хранилища, проверка бизнес-правил это ответственность слоя домена."

Валидатор или набор валидаторов - это отдельный функциональный блок, который можно многократно использовать внутри logic layer. В этом отличие от варианта 3.

Как все сложно в web. Я бы просто использовал триггер в бд при записи неуникального емайл(поле в бд должно быть уникальным) , откат транзакции и уведомление клиента. В том же postgress есть pg_ notify.

Отлично, вы жёстко привязали инфраструктуру к домену

о чем вы? О PostgreSQL условно?) Так иначе не выйдет

При регистрации пользователя нужно проверять, что записываемый email уникальный

Далее рассматривается решение, основанное на трёхслойной архитектуре, в которой каждый слой (layer) состоит из трёх подслоёв (sublayer).

Извините, но 9 слоев для начинающего архитектора как-то маловато.

3 слоя / 3 подслоя это общий подход для построения архитектуры. Конечно в задаче сохранения пользователя в бд с валидацией его email не надо использовать всё теоретически возможные слои и подслои. Например калькулятору (такому как в винде) достаточно одного слоя состоящего из двух подслоёв.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации