В чем разница между DTO vs ValueObject vs Entity на примерах? Правильное именование классов.

fixxxer

К.О.
Партнер клуба
но вопрос то был в другом, прокидывать проверку на кол-во перезаписей Article в правила авторизации или на уровень валидации ее тащить?
У тебя получается, что бизнес-правило уносится куда-то на уровень приложения. В случае с select for update это вообще получается жестоко - надо вызвать какой-то специальный метод репозитория (!), дернуть проверки... Как гарантировать, что кто-то потом не будет писать, скажем, XML-RPC api для постинга, и вызовет именно твой хитрый метод?

Если бы были нормальные модели, можно было бы играться с фабричными методами, фабриками или иными способами, создающими/загружающими Article для конкретного Author. А c AR, где как ни крути в любой момент можно написать $article->author_id = 42, пожалуй, тут применима аксиома Эскобара.
 

Redjik

Джедай-мастер
ну если уж продолжать о сферических конях в вакууме, то не вижу проблемы
в обычный экешн пихается обычный репозиторий
именно в этот экшен пихается декорированный репозиторий, который делает select for update при выборке, и никаких специальных методов
тебе когда надо в мемкеш при выборке из репо пихнуть - ты тоже отдельным методом делаешь?
я вот декорирую CacheAwareRepositroyDecorator
 

Redjik

Джедай-мастер
У тебя получается, что бизнес-правило уносится куда-то на уровень приложения.
ВОТ ИМЕННО, в этом то и основной вопрос, что это - бизнес правило или обычное правило авторизации?
Или их глупо разделять? И вопрос сам по себе глупый?
Вот правило - что юзер может редактировать только свой профиль, а админ любой - это бизнес правило?
И если да, то как такие штуки разруливать на уровне домена?
Ибо даже если я разрулю это на уровне домена, то как потом DomainException преобразовать в UnauthorizedException?

хрень какая то получается... как ты там говорил
призываю Вурдалака
 

fixxxer

К.О.
Партнер клуба
Article и Author - точно сущности уровня домена, почему правила вдруг нет?

Я бы вообще не притаскивал сюда RBAC и делал тупо:

PHP:
class Article {
    public function changeContents($newContents) {
        if (limit exceeded) {
           throw new ...
        }
    }
}
Если "limit exceeded" зависит от какого-нибудь сервиса, имеющего конфигурацию (ок, пусть это реализация этакого расширенного RBAC, хотя спорно) - ну так через double dispatch его туда в метод.
 

Redjik

Джедай-мастер
ну так и сделал в итоге
еще и спецификацию хотел добавить, но "пацаны не поймут" =))
 

Redjik

Джедай-мастер
А как гарантировать, что именно в другой экшен из моего примера пихается именно декорированный?
зависит от фв, в симфони в конфиге указываешь, в ларке баиндишь интерфейс https://laravel.com/docs/5.2/container#contextual-binding

в любом случае race condition не забота домена, это инфруструтура, а инфраструтуру надо на конфигах фигачить, имхо
 

fixxxer

К.О.
Партнер клуба
Но ведь этот экшен еще не написан!
А при таком неявном требовании - когда будут писать, фиг вспомнят про твой декорированный, и никакими when ты заранее не угадаешь, только магии добавишь.
Слишком хрупко
 

Redjik

Джедай-мастер
ну не декорируй, сделай отдельный репо, тут нет серебряной пули
 

fixxxer

К.О.
Партнер клуба
И про отдельный никто не вспомнит!

А вообще, щас придет Вурдалак и расскажет про CQRS :)
 

Вурдалак

Продвинутый новичок
Article и Author - точно сущности уровня домена, почему правила вдруг нет?
Тут ключевое, пожалуй, bounded context. Я не был бы уверен, что у него реально там есть Author как сущность в том же BC, что и Article. Т.е. Article::$authorId тут может просто быть просто как сквозное значение, которое самому домену особо и не нужно, в реальности там обычный $userId, общий для всего сайта. Правила бывают разные, некоторые из них не хочется тащить в тот же BC. Если завтра у него размещение статей станет платным, а для яблочников (Safari) цены будут в 2 раза выше, а для каких-то партнёров размещение останется бесплатным, то скорее всего всё будет грустно, если всё тащить в один контекст.

Т.е. правила по-хорошему, конечно, domain, но вопрос какой именно :) А связывать эти BC можно по-разному: через UI, через декорирование (command bus, например), Saga, etc.

Хотя, возможно, я бы тоже сделал сначала по-простому, с двумя разными методами Article::editByUser(LimitPolicy) и Article::editByModerator().

CQRS хотел упомянуть, да, в том контексте, что command handler'ы можно декорировать, например, используя аннотации к методу handle, указывая там необходимые роли и прочую фигню. А для обычных application services нужен AOP. А поскольку никакого AOP у вас нет, @Redjik пытается внедрить ограничения на уровне REST API. Но ограничивать на уровне команд гораздо комфортнее на мой взгляд, т.к. они отражают реальное бизнес-действие, мы понимаем, что ограничили команду EditArticleCommand, а не «POST /article/42» (причем этот «POST /article/42» может маппится на разные команды...). Да и внешний API не вечен.

Касаемо RC, это непростой вопрос.
Если можно забить, то я забиваю. Что случится, если пользователь отредактирует статью лишний раз, используя параллельные запросы? Если мотивация была в том, чтобы ограничить искусственный «ап» статьи в рейтинге последних редактируемых, то вообще похер.
Если правила находятся внутри самого aggregate root (в смысле, все значения хранятся вместе с ним), то проблемы нет, т.к. aggregate root сохраняется атомарно и являются по сути инвариантами этого AR.
Если правила вне его, то по-хорошему — saga.
Если по-простому — mutex. Опять-таки, можно навесить декоратором на command handler.
Но это всё IMHO.
 
Последнее редактирование:
Сверху