Обновить
4K+
4
Денис@DenisYu-1

Пользователь

5
Рейтинг
Отправить сообщение

Спасибо за отзыв!

Только отмечу, что мне как-то наоборот делить обычно удобнее. Потому что иногда приходится объединять "расползшиеся" в разные стороны представления/логики – то ещё удовольствие :) Но опять же, по ситуации надо смотреть.

Да, есть такой подход. Полезен в некоторых случаях.

Решать обозначенные в примере проблемы с помощью STI я бы не стал, хотя действительно было бы что-то среднее между двумя крайностями – в одной таблице хранилось бы несколько строк для разных представлений юзера.

Соглашусь про "не самый лучший паттерн", не соглашусь, что моя идея в этом. В ActiveRecord сущность управляет своим жизненным циклом. Тут не совсем про это. 

В самой библиотеке реализован DataMapper.

Согласен.

По-прежнему остаётся важным момент, где проходит граница инварианта. Если есть правило, которое одновременно зависит и от password, и от stripe_customer_id, то это уже не два независимых среза данных. Значит, для такого сценария должно быть представление, где видны оба поля, и изменение должно идти через него.

Если поверх этого есть общий optimistic lock на строку, то проблема как раз решается штатно: проверяем инвариант на актуальном состоянии и не даём молча записать устаревшее изменение.

У меня пока в планах добавить optimistic lock к функционалу либы, а также может быть пересмотреть реализованный pessimistic вариант.

Если вы имеете в виду Table Module из Фаулера, то это всё-таки другой паттерн.

Там через один объект работаем со всей таблицей целиком, у меня же идея почти обратная: разрешить несколько независимых представлений одной и той же строки таблицы.

Если вы видите более близкий паттерн или пример реализации именно такого отображения — будет интересно посмотреть.

Спасибо за подробный комментарий.

Конечно, правильное проектирование это... правильно :) Впрочем, иногда денормализация БД – тоже осознанно выбранный подход. В примерах представлено что-то среднее.

Попробую подсветить пару моментов:

  1. Если вынести stripe_customer_id в отдельную таблицу, основной User всё равно как бы будет знать о биллинге:

    $user->getStripeCustomer();

    Хотя в большинстве сценариев работы с пользователем этот релейшен вообще не нужен.

  2. nullable password в этих историях (надеюсь) не означает "любой пользователь может существовать без пароля". Это лишь ещё один пример, когда общепринятый подход может быть изменён. Например, поддерживается несколько типов пользователей с разными конфигурациями (аля системный пользователь или пользователь, аутентифицирующийся через внешний провайдер). В пользователя без пароля я бы вообще логиниться не давал. Но опять же, это детали логики где-то в коде.

Как мне кажется, вьюшки решают немного другую, хотя и похожую, задачу.

Если нужен удобный read-model: сабсет полей, готовый join, ограничение прав на уровне БД, то вьюхи отлично подходят. Использовать вьюшки прям как сущности приложения пока не доводилось, тут не могу ничего сказать.

Да, это хорошее замечание.

Если данные действительно имеют разный жизненный цикл, разные правила владения и независимо развиваются, то вынесение их в отдельные таблицы и связи по user_id – лучшее решение.

Просто бывают случаи, когда на уровне БД одна таблица уже выбрана осознанно и это нормально, но на уровне кода одна большая User-entity начинает становиться слишком жирной и неудобной для разных модулей.

С insert и NOT NULL ещё интереснее: предусмотрен механизм "валидирования" такой ситуации, чтобы заранее отловить проблему. Но тут как бы от базы не уйдешь – либо нужно эту колонку писать во всех сценариях, либо она всё-таки необязательная :) Ну либо можно сделать read-only модель под сценарий, когда запись не предполагается.

Информация

В рейтинге
1 270-й
Зарегистрирован
Активность

Специализация

Фулстек разработчик
Ведущий
Git
SQL
Английский язык
Docker
ООП
CI/CD
PHP
Symfony