сервисный класс, value object и анемичная модель

grigori

( ͡° ͜ʖ ͡°)
Команда форума
А с микрофреймворками вы sql выносите в отдельный слой, или прямо в сущностях/коллекциях/моделях пишите?
 
Последнее редактирование:

fixxxer

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

Просто так вышло, что такие проекты обычно средне-крупные, и там без разницы на объем зависимостей, зато удобно использовать кучу готового. Был бы мелкий - прикрутил бы ручками, думаю.

А с микрофреймворками вы sql выносите в отдельный слой, или прямо в сущностях/коллекциях/моделях пишите?
analogue - это такой датамаппер на основе eloquent, в репозиториях для find/persist/delete sql и не нужен (достаточно генерируемого), это, конечно, намного тяжелее, чем простой QB, но писать ручками маппинг-персистенцию очень лень и не вижу смысла. А аналитику и подобное (что не ложится на entities) пишу отдельными классами через квери билдер или raw sql - там уже на выходе не сущности, а специфичные для этой аналитики объекты и их коллекции.
 

Вурдалак

Продвинутый новичок
analogue - это такой датамаппер на основе eloquent, в репозиториях для find/persist/delete sql и не нужен (достаточно генерируемого), это, конечно, намного тяжелее, чем простой QB, но писать ручками маппинг-персистенцию очень лень и не вижу смысла. А аналитику и подобное (что не ложится на entities) пишу отдельными классами через квери билдер или raw sql - там уже на выходе не сущности, а специфичные для этой аналитики объекты и их коллекции.
Звучит как разделение на write и read models. Им бы чо попроще, ведь по их логике одна модель проще двух, зачем множить сущности Ж)
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
Не, я не разделяю (в том случае, о котором говорю). Речь об аналитике-статистике и подобных вещах, где на выходе вообще не entities.

Хотя щас вот тут для домашнего проекта разбираюсь с микросервисными архитектурами, CQRS и разделение на r/w models туда ложится идеально.
 
Последнее редактирование модератором:

Вурдалак

Продвинутый новичок
Не, я не разделяю (в том случае, о котором говорю). Речь об аналитике-статистике и подобных вещах, где на выходе вообще не entities.
Граница между entities и «вообще не entities» на самом деле размыта. Если ты выводишь список пользователей, а потом понадобилось выводить ещё кол-во заказов рядом с каждым, то что ты будешь делать: вводить в сущность денормализованное поле с кол-вом заказов или будешь подсчитывать кол-во в каждой итерации?
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
Я такое "денормализую" на уровне domain entity, а на уровне маппера достаю count. Маппинг односторонний, read-only.

В каких-то случаях (когда это нужно редко) уместнее отдельно достать счетчики через where in, а объединить уж много способов не трогая entity.

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

grigori

( ͡° ͜ʖ ͡°)
Команда форума
в половине мест сессии вообще не нужны, где они используются

аналитику и подобное (что не ложится на entities) пишу отдельными классами через квери билдер или raw sql - там уже на выходе не сущности, а специфичные для этой аналитики объекты и их коллекции.
если не сущности, то что они возвращают - value object в виде 3-мерного массива?

+1 к вопросу о заказах в списке пользователей
 

Вурдалак

Продвинутый новичок
если не сущности, то что они возвращают - value object в виде 3-мерного массива?
Массивы неудобны тем, что состав полей неявный, никак не гарантируется и нет автокомплита. Обычно делается какой-то VO а-ля DailyUserReport (DailyUserDto, DailyUserReadModel, etc.) или что-то такое для твоего конкретного use case, который будет содержать необходимый набор read-only полей.

В случае с заказами я бы сделал
PHP:
final class UserDto
{
    private $id;
    private $name;
    private $ordersQuantity;

    public function __construct($id, $name, $ordersQuantity)
    {
        // ...
    }

    // ...
}
Вопрос того как именно заполняется это поле оставил бы инфраструктуре: либо через LEFT JOIN и COUNT(*), либо можно сделать денормализованное поле прямо в таблице и пересчитывать его.
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
то есть класс, который генерирует этот VO - обертка для статических функций с sql?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
не то чтобы "зачем", в "читалке" с sql классе не будет состояния, a данные выносятся в VO, то есть анемичная модель?
 

Вурдалак

Продвинутый новичок
не то чтобы "зачем", в "читалке" с sql классе не будет состояния, f данные выносятся в VO, то есть анемичная модель?
UserDto генерируется сервисом:
PHP:
final class MySqlUserQueryService implements UserQueryService
{
    public function __construct(PDO $pdo)
    {
        // ...
    }

    public function find($id)
    {
        // ...

        return new UserDto(...);
    }

    // ...
}
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
да, я о том же:
these models come with design rules that say that you are not to put any domain logic in the the domain objects. Instead there are a set of service objects
я правильно понимаю, что у вас получается анемичная модель?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
read model - это о другом.
A read model is a model specialized for reads, that is, queries. It takes events produced by the domain and uses them to build and maintain a model that is suitable for answering the client's queries.
В ArrayObject, который оформлен в виде класса, нет методов для запросов. Класс, который его отдает - тоже не read model.

Это и не VO потому что это он состоит из множества значений разных типов, то есть он не simple.
А value object is a small object that represents a simple entity. Examples of value objects are objects representing an amount of money or a date range.
https://en.wikipedia.org/wiki/Value_object
Это мог бы быть DTO, но нет подготовки данных для передачи между слоями.

Если это не VO, не DTO, не Read model, и в целом подходит под фаулеровское описание анемичной модели, то это анемичная модель?
 

Вурдалак

Продвинутый новичок
То, о чём мы говорим, одновременно является и read model, и DTO, и VO. Просто эти понятия из разных плоскостей.

iPhone является мобильником; с другой точки зрения он, вероятно, является смартфоном; а с ещё одной точки зрения он является железкой. Эти понятия друг друга взаимно не исключают.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Судя по коду роут класса - это не бага, а фича :)
точно такое же поведение во всех реализациях PSR-7 (что ze, что slim, что radar)
Т.е. работу с выводом реализовать только через методы response. А если нужен прямой вывод через echo или print то использовать 'outputBuffering' append или prepend но не false
проблемы в том, что:
1. false - это документированное допустимое значение, и с output_buffering оно работать обязано
2. append или prepend ведут себя точно так же
3. если не делать вывод до и после - вывод из приложения вообще теряется, так просто нагляднее
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
То, о чём мы говорим, одновременно является и read model, и DTO, и VO. Просто эти понятия из разных плоскостей.

iPhone является мобильником; с другой точки зрения он, вероятно, является смартфоном; а с ещё одной точки зрения он является железкой. Эти понятия друг друга взаимно не исключают.
то есть, то, о чём мы говорим, похоже на anemic model, read model, DTO, и VO.
как человек, похожий на генерального прокурора. понятно.
 

Вурдалак

Продвинутый новичок
то есть, то, о чём мы говорим, похоже на anemic model, read model, DTO, и VO
Да, это выглядит примерно так: мы говорим про read models, и тут приходишь ты и заявляешь, что вообще-то то, о чём мы говорим, походит на объект и приводишь определение объекта из ООП.

Не очень ясно что ты пытался в итоге сказать.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
я хочу сказать вот что: что если что-то похоже на анемичную модель (нет логики или данных), и не используется для абстрагирования при передаче данных между слоями - то это называется анемичная модель

я совершенно не против, если ты, @Вурдалак, будешь называть ее read model, я даже не тебе вопрос задавал :)
 
Последнее редактирование:
Сверху