QueryBuilder и AR в отдельном пакете?

Не относящиеся к фреймворку и программированию вопросы
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение ElisDN »

anton_z писал(а): 2019.08.10, 00:59 С AR я могу такую блокировку прямо в этом методе сделать (хоть пессимистическую, хоть оптимистическую), связанный код будет в одном месте. А у вас по-моему блокировки нет. Пессимистической точно, оптимистическую не нашел.
Оптимистическую добавил.
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: QueryBuilder и AR в отдельном пакете?

Сообщение skynin »

ElisDN писал(а): 2019.08.10, 00:17 Видимо у вас своё понимание логики.
Видимо :) за 20+ в сфере финансово-экономического ПО ничего не понял о его разработке :)

Ваш подход к декомпозиии известен под названием Rich Domain Model
У него, как у всего есть положительные стороны, а есть и отрицательные.

Из отрицательных назову:
1. работа с БД становится дико неэффективной, потому что обычно происходит вот это: Теперь можно спокойно делать таблицу в БД.
А для эффективной работы БД проектирование схемы БД, правил хранения и обмена персистентными данными нужно делать ПЕРЕД написанием кода, или одновременно, отбрасывая проектные решения по домену по критерию - такое будет дико просаживать БД и ничего с этим нельзя будет сделать. Настолько ПЕРЕД, что иногда кажется что это преждевременная оптимизация.
(Исключения из такого порядка проектирования вначале БД, а потом прикладной код - универсальные коробочные продукты, предназначенные для решений о которых разработчики таких продуктов и не догадываются на этапе разработки)
Беда с персистентными хранилищами любого типа что после написания кода работающего с данными перепроектировать будет очень трудозатрано
2. В сложных проектах вся простота потока выполнения внутри методов типа changeStatus быстро испаряется, когда предстоящие изменения требуется валидирировать, запрашивать дополнительные данные в зависимости от условий if и часто густо, и на php тоже, еще и асинхронно. Плюс выделять скоупы транзакций, обрабатывать откаты, о которых надо уведомить другие части системы.
Избавиться от проблемы конечно можно - как в Magento нередко виден результат избавления - конструкторы в которые инжектится с десяток сервисов :)
3. Чем чревато превращение ActiveRecord в сложный Domain Model - все знают :) Но точно та же проблема и с самим "чистым" Domain Model в сложных проектах: у какого объекта должен быть changeStatus который изменяет состояния других объектов? почему у него, а не у другого?

"Чистыми классами", "DTOшками" я и назвал то что вы написали - чистые Domain Model=сферические кони в ваккуме. Которые в сложной системе будут обвешаны кучей вещей, и зависимы от кучи вещей.
Например уже говорилось - да бизнес-логика в силу технологических причин начнет утекать в ХП. Как у джавистов есть шутка - был программистом на джава а стал спецом на PL/SQL. Это реальная ситуация в - сложных системах.

То есть - реальные сложные системы далеки от той красоты что пишут о них в книгах, или подобно вашему красивому примеру "сложного приложения".
ElisDN писал(а): 2019.08.10, 00:17 В итоге 300 таких юнит-тестов выполняются за секунду, так что никому не мешают.
Это хорошо.
Но вот что забыл спросить еще в предыдущем посте

А зачем при разработке конкретной фичи запускать все 300 юнит тестов?
Вы одновременно правите сотню файлов?
Но тогда вопрос - а как это у вас декомпозирована система что вам надо сразу столько править?
А если правите с десяток - то зачем вам запускать ВСЕ 300 юнит тестов?
Перед пушем - понятно, нужно запустить побольше тестов, а лучше все что есть :) Но обычно все что есть это уже счет на десятки минут, и все прогоняются уже автоматикой на сервере.

А во время разработки - зачем?

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

И
если у вас уже для такого простого примера, который вы делаете требуется 300 юнит тестов, то что будет в реальной сложной системе?
и сколько времени будут бежать тысячи вот таких юниттестов?

Я не против юнит тестов.
Я против академической архитектурной астронавтики.
ElisDN писал(а): 2019.08.10, 00:17 И по этим мыслям сразу пишу копипастой пачку из пяти тестов.
неважно каким способом пишите

Это уже следующий вопрос
стоимость поддержки тестов.
Это ведь тоже код проекта, и он тоже должен быть актуальным, рабочим

И эта стоимость в сложных проектах тоже становится настолько большой что начинают задумываться об экономии.
И периодически возникает необходимость и тесты рефакторить, не из-за скорости их работы, а потому что одна строчка в коде требует изменений в пяти тестах, да еще и нетривиальных изменений. И тогда команда взвывает - так мы что вообще пишем - программу или тесты???

но это уже такое, лирическое из практики на разных проектах :)
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Аватара пользователя
BrusSENS
Сообщения: 565
Зарегистрирован: 2012.07.26, 06:51
Откуда: Новороссийск
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение BrusSENS »

ElisDN писал(а): 2019.08.09, 17:12 Не "делает невозможным тестирование", а "делает невозможным юнит-тестирование без базы".
А, простите, зачем тестировать без базы Dm?
ElisDN писал(а): 2019.08.09, 17:12 База замедляет тесты и добавляет лишний геморрой с фикстурами.
Это всё понятно, но разговор то про DM шёл. Причём тут юнит тесты и DM? Зачем тестировать DM без базы, объясните пожалуйста, не понимаю просто.
ElisDN писал(а): 2019.08.09, 17:12 В несовместимости SQLite и PostgreSQL.
Правда? Буду знать, спасибо. Тем не менее, объясните, зачем тестировать DM без базы. Ну ей богу не могу понять.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение ElisDN »

BrusSENS писал(а): 2019.08.13, 14:49 А, простите, зачем тестировать без базы Dm?
Тестировать без базы доменные сущности, а не сам DM.
Аватара пользователя
BrusSENS
Сообщения: 565
Зарегистрирован: 2012.07.26, 06:51
Откуда: Новороссийск
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение BrusSENS »

ElisDN писал(а): 2019.08.13, 15:34 Тестировать без базы доменные сущности, а не сам DM.
Так а зачем в сущности пихать много бизнес логики? Можно в небольшие сервисы логику выносить, как например PasswordHasher и т.п. И будет сущность чистая, без лишних соплей. Получается к разработке подходим абы как, а потом пытаемся всё это тестировать. А такие сервисы можно тестировать независимо.
Просто я реально не понимаю, зачем например тестировать такой код:

Код: Выделить всё

class User extends ActiveRecord
{
    public function changePassword(string $password, PasswordHasherInterface $hasher)
    {
        $this->password = $hasher->hash($password);
    }
}
Считаю, что проблема тестирования по сути является проблемой бездумного написания кода. Если пишем через "пятую точку", то и тесты будем писать так-же.

По сути писал я проекты, с такой реализацией и тестировать "AR сущности" не приходилось, ибо зачем, если там очевидный код, который по сути будет всегда работать.

Это я о чём? Да о том, что просто возмущает надуманная проблема с тестированием AR. Ведь его по сути тестировать нет смысла, если не пихать туда всё, что можно. Паттернизм - бич сегодняшнего PHP. Вроде паттерны знают, вроде применяют, вроде об архитектуре размышляют. Только архитектуры то нет. Есть паттернизм, а не реальное понимание проблем разработки софта.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: QueryBuilder и AR в отдельном пакете?

Сообщение anton_z »

BrusSENS писал(а): 2019.08.14, 14:06 надуманная проблема с тестированием AR. Ведь его по сути тестировать нет смысла, если не пихать туда всё, что можно. Паттернизм - бич сегодняшнего PHP. Вроде паттерны знают, вроде применяют, вроде об архитектуре размышляют. Только архитектуры то нет. Есть паттернизм, а не реальное понимание проблем разработки софта.
Здесь не соглашусь. AR обычно содержит бизнес-логику, в том числе код для генерации SQL-запросов. Это уже очень много и это нужно тестировать, в частности необходимо проверять правильно ли поменялись данные в нужных таблицах. сгенерировались ли события и т.д. и т.п.

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

P.S. Я сущности делаю с подключением внутри и иногда другими зависимостями - почти вся бизнес-логика в них помещается, сервисы почти пустые.
Аватара пользователя
BrusSENS
Сообщения: 565
Зарегистрирован: 2012.07.26, 06:51
Откуда: Новороссийск
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение BrusSENS »

anton_z писал(а): 2019.08.14, 16:39 Здесь не соглашусь. AR обычно содержит бизнес-логику, в том числе код для генерации SQL-запросов. Это уже очень много и это нужно тестировать, в частности необходимо проверять правильно ли поменялись данные в нужных таблицах. сгенерировались ли события и т.д. и т.п.
Пример можно? Не совсем понимаю, что подразумевается под "код для генерации SQL-запросов".
anton_z писал(а): 2019.08.14, 16:39 Выносить все в сервисы - я считаю это плохая практика. Приводит к такому явлению как анемичные сущности == структуры данных, что сделает код ближе к процедурному стилю, а именно сервисы будут играть роль функций, сущности - структур данных. Для того чтобы избежать этого нужно стараться побольше бизнес-логики делать в сущностях, агрегатах.
Я говорю именно о том, что не нужно пихать сложную логику в них. Если есть сложная логика, которую сложно тестировать - в отдельные сервисы. В остальном получается всегда так, что сущность имеет простые методы, которые просто нет смысла тестировать.

anton_z писал(а): 2019.08.14, 16:39 P.S. Я сущности делаю с подключением внутри и иногда другими зависимостями - почти вся бизнес-логика в них помещается, сервисы почти пустые.
Сущность она же на то и сущность. Вот возмём к примеру человека. Если у человека оторвалась пуговица, то что мы делаем? Правильно. Пришиваем. Но зачем человеку всегда ходить с иголкой внутри? Правильно, незачем. Посему и делаем передачу "иголки" только тогда, когда нужно, а не каждый раз при инициализации.
И да, зачем нужны пустые сервисы? Сервис же на то и сервис, что бы описывать логику решения определённой задачи.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение ElisDN »

BrusSENS писал(а): 2019.08.14, 14:06 Так а зачем в сущности пихать много бизнес логики?
ООП как раз и придумано, чтобы пихать логику со стейтом в слабосвязанные объекты. А те самые паттерны и принципы придуманы, чтоб внешнюю связанность модулей уменьшить для более осознанного контроля сложности.
BrusSENS писал(а): 2019.08.14, 14:06 Можно в небольшие сервисы логику выносить, как например PasswordHasher и т.п. И будет сущность чистая, без лишних соплей. А такие сервисы можно тестировать независимо.
И получится не объект, а, как и сказали, структура с полями (как ассоциативный массив) с методом save(). Со сквозным сильносвязанным расшаренным стейтом без инкапсуляции.
BrusSENS писал(а): 2019.08.14, 14:06 Просто я реально не понимаю, зачем например тестировать такой код?
Такой код тестировать незачем:

Код: Выделить всё

class User extends ActiveRecord
{
    public function changePassword(string $password, PasswordHasher $hasher): void
    {
        $this->hash = $hasher->hash($password);
    }
}
А в таком уже появляется зачем:

Код: Выделить всё

public function requestPasswordReset(ResetToken $token, \DateTimeImmutable $date): void
{
    if (!$this->isActive()) {
        throw new DomainException('User is not active.');
    }
    if (!$this->email) {
        throw new DomainException('Email is not specified.');
    }
    if ($this->resetToken && !$this->resetToken->isExpiredTo($date)) {
        throw new DomainException('Resetting is already requested.');
    }
    $this->resetToken = $token;
    $this->recordEvent(new PasswordResetRequested($this->id, $token));
}
А в такой уже без тестов соседа впускать грустно:

Код: Выделить всё

public function makeBid(Member $member, Price $price, DateTimeImmutable $date): void
{
    if (!$this->isActive()) {
        throw new \DomainException('Lot is not active.');
    }

    if ($member === $this->member) {
        throw new \DomainException('Unable to make bid by owner.');
    }

    foreach ($this->bids as $bid) {
        if ($bid->isByMember($member)) {
            throw new \DomainException('Bid is already placed.');
        }
    }

    if ($this->bids->count() && !$price->isGreaterThan($this->getMaxBidPrice())) {
        throw new \DomainException('Price must be greater than the previous one.');
    }

    if (!$this->bids->count() && !$price->isGreatherOrEqual($this->startPrice)) {
        throw new \DomainException('Price must be greater or equal to start one.');
    }

    $bid = new Bid($this, $member, $price, $date);

    $this->bids->add($bid);
    $this->recordEvent(new BidCreated($this, $bid));

    if ($this->blitzPrice && $price->isGreaterOrEqual($this->blitzPrice)) {
        $this->close($date);
    }
}
В случае такой богатой сущности в прикладном сервисе-процедуре тестировать нечего:

Код: Выделить всё

class Bid\Make\Handler
{
    public function handle(Command $command): void
    {
        $lot = $this->lots->get(new Lot\Id($command->lot));
        $member = $this->members->get(new Member\Id($command->member));
        $lot->makeBid($member, new Price($command->price), new DateTimeImmutable());
        $this->flusher->flush($lot);
    }
}
А так уже без разницы, где, как и на чём вы эту логику спрограммируете. Хоть сущностями, хоть сервисами, хоть хранимками и триггерами.
BrusSENS писал(а): 2019.08.14, 14:06 По сути писал я проекты, с такой реализацией и тестировать "AR сущности" не приходилось, ибо зачем, если там очевидный код, который по сути будет всегда работать.
Если вся логика вписана в сервисы, то и тестируем сервисы интеграционно.
Если же логика инкапсулирована в сущностях, то тестируем сущности юнитами.

Если вся логика для вписана прямо в БД хранимками, триггерами и констрейнтами без богатых сущностей, то ORM не нужен.
Если же логика для разделения вынесена в PHP-объекты, а БД используется как голое хранилище, то ORM нужен.

Всё логично.
BrusSENS писал(а): 2019.08.14, 14:06 Получается к разработке подходим абы как, а потом пытаемся всё это тестировать.
Считаю, что проблема тестирования по сути является проблемой бездумного написания кода. Если пишем через "пятую точку", то и тесты будем писать так-же.
Так и получается с AR "из коробки" в большинстве проектов, что тонны кода уже написаны, а тестировать его уже и лениво, и геморройно.
В этом и суть, что пытаемся тестировать "потом", а не "сначала". Как "семь раз отрежь, один отмерь".
Аватара пользователя
BrusSENS
Сообщения: 565
Зарегистрирован: 2012.07.26, 06:51
Откуда: Новороссийск
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение BrusSENS »

ElisDN писал(а): 2019.08.14, 19:48 ООП как раз и придумано, чтобы пихать логику со стейтом в слабосвязанные объекты. А те самые паттерны и принципы придуманы, чтоб внешнюю связанность модулей уменьшить для более осознанного контроля сложности.
Ни о какой "слабосвязаности" про ооп не говорится, не нужно выдумывать. ООП - всего-лишь подход для представления всего в виде объектов. И паттерны придуманы не для создания "слабой связанности", а для решения определённых проблем при проектировании. Где у нас синглтон связанность уменьшает? Верно, нигде. Это всего лишь решение, для того, что бы объект класса существовал в единственном экземпляре.
ElisDN писал(а): 2019.08.14, 19:48 И получится не объект, а, как и сказали, структура с полями (как ассоциативный массив) с методом save(). Со сквозным сильносвязанным расшаренным стейтом без инкапсуляции.
Я не в коем случае не говорил о том, что нужно пихать всё в отдельные классы. Нет. Просто считаю, что в сущностях сложной логики не должно быть. Сущность должна быть легковесной, понятной и самодостаточной.
ElisDN писал(а): 2019.08.14, 19:48 А в таком уже появляется зачем:

Код: Выделить всё

public function requestPasswordReset(ResetToken $token, \DateTimeImmutable $date): void
{
    if (!$this->isActive()) {
        throw new DomainException('User is not active.');
    }
    if (!$this->email) {
        throw new DomainException('Email is not specified.');
    }
    if ($this->resetToken && !$this->resetToken->isExpiredTo($date)) {
        throw new DomainException('Resetting is already requested.');
    }
    $this->resetToken = $token;
    $this->recordEvent(new PasswordResetRequested($this->id, $token));
}
И зачем? Что тут может пойти не так? А вообще это почему у нас этим должна заниматься сущность? Сколько говорили о том, что валидацией сущность не должна заниматься, а в итоге делаем всё наоборот. Это дело сервиса, но никак не сущности.
ElisDN писал(а): 2019.08.14, 19:48 А в такой уже без тестов соседа впускать грустно:

Код: Выделить всё

public function makeBid(Member $member, Price $price, DateTimeImmutable $date): void
{
    if (!$this->isActive()) {
        throw new \DomainException('Lot is not active.');
    }

    if ($member === $this->member) {
        throw new \DomainException('Unable to make bid by owner.');
    }

    foreach ($this->bids as $bid) {
        if ($bid->isByMember($member)) {
            throw new \DomainException('Bid is already placed.');
        }
    }

    if ($this->bids->count() && !$price->isGreaterThan($this->getMaxBidPrice())) {
        throw new \DomainException('Price must be greater than the previous one.');
    }

    if (!$this->bids->count() && !$price->isGreatherOrEqual($this->startPrice)) {
        throw new \DomainException('Price must be greater or equal to start one.');
    }

    $bid = new Bid($this, $member, $price, $date);

    $this->bids->add($bid);
    $this->recordEvent(new BidCreated($this, $bid));

    if ($this->blitzPrice && $price->isGreaterOrEqual($this->blitzPrice)) {
        $this->close($date);
    }
}
Верно. Грустно. Потому что этого тут не должно быть. Опять валидируем? В сервисе проверили и сохранили, если нужно. Не место этому в сущности.
ElisDN писал(а): 2019.08.14, 19:48 Так и получается с AR "из коробки" в большинстве проектов, что тонны кода уже написаны, а тестировать его уже и лениво, и геморройно.
В этом и суть, что пытаемся тестировать "потом", а не "сначала". Как "семь раз отрежь, один отмерь".
Не всегда можно тесты писать до написания рабочего прототипа. Мы не в идеальном мире всё-таки живём Посему не всегда TDD подходит.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: QueryBuilder и AR в отдельном пакете?

Сообщение anton_z »

BrusSENS писал(а): 2019.08.14, 19:34
Пример можно? Не совсем понимаю, что подразумевается под "код для генерации SQL-запросов".
У меня в одной CRM есть запросы(заявки) от клиентов, которые в приложении представлены классом common\models\Request.
Для заявок согласно заданию предусмотрено поднятие в списке заявок операторов по расписанию, которое задается оператором через gui или автоматически при наступлении определенных условий (здесь это не так важно). Здесь представлен метод, выполняющий поднятие заявки по расписанию. В случае ошибки или успеха, согласно бизнес-правилу необходимо внести запись в журнал поднятий.

CRM под конкретного клиента, поэтому сообщения на русском, смысла нет их в Yii::t() выносить.

Код: Выделить всё


class Request 
{

    /**
     * @param RequestLiftSchedule $schedule
     *
     * @throws \Throwable
     */
    public function lift(RequestLiftSchedule $schedule)
    {

        self::getDb()->transaction(function () use ($schedule) {

            $lifted_at = date('Y-m-d H:i:s');

            if (in_array($this->internal_status, [
                self::INTERNAL_STATUS_OPENED,
                self::INTERNAL_STATUS_CALL_FAILED
            ])) {

                $this->lifted_at = $lifted_at;

                if ( ! $this->save()) {

                    if ($this->hasErrors()) {
                        $error = array_values($this->getFirstErrors())[0];
                    } else {
                        $error = 'Не удалось обновить дату поднятия заявки по неизвестной причине.';
                    }

                    throw new \DomainException($error);

                }

                $comment = 'Успешно';

            } else {

                $comment = "Заявка в статусе \"{$this->internalStatusName()}\"";

            }

            $this->link('liftLogs', new RequestLiftLog([
                'lift_at'   => $schedule->lift_at,
                'lifted_at' => $lifted_at,
                'comment'   => $comment
            ]));

            $schedule->delete();

        });

    }


}

Валидация AR здесь используется для проверки корректности данных правилам БД (а не для формы), чтобы туда что-попало не записалось. Это позволяет делать меньше VO, использовать скалярные типы. Вообще привычка на save() всегда такие проверки делать.

Под кодом, отвечающим за генерацию SQL-запросов имеется ввиду вызовы save(), link(), которые генерируют и выполняют sql-запросы.
BrusSENS писал(а): 2019.08.14, 22:07
Верно. Грустно. Потому что этого тут не должно быть. Опять валидируем? В сервисе проверили и сохранили, если нужно. Не место этому в сущности.
Тут я согласен с @ElisDN, такому место в сущностях. Я бы почти также сделал, только у меня внутри метода были бы вызовы save()/update() и транзакция.


P.S. В целом по теме согласен со @skynin что php в оригинале больше годен для прямого общения с БД, чем для "синхронизации состояния" (flush) как с EnityManager. Это больше годно для сред, где процессы постоянно запущены, и то надо пробовать. Я и на C++ и на Java также как в примере делал, правда опыта у меня в этих средах маловато.
Аватара пользователя
BrusSENS
Сообщения: 565
Зарегистрирован: 2012.07.26, 06:51
Откуда: Новороссийск
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение BrusSENS »

anton_z писал(а): 2019.08.15, 02:34

Код: Выделить всё


class Request 
{

    /**
     * @param RequestLiftSchedule $schedule
     *
     * @throws \Throwable
     */
    public function lift(RequestLiftSchedule $schedule)
    {

        self::getDb()->transaction(function () use ($schedule) {

            $lifted_at = date('Y-m-d H:i:s');

            if (in_array($this->internal_status, [
                self::INTERNAL_STATUS_OPENED,
                self::INTERNAL_STATUS_CALL_FAILED
            ])) {

                $this->lifted_at = $lifted_at;

                if ( ! $this->save()) {

                    if ($this->hasErrors()) {
                        $error = array_values($this->getFirstErrors())[0];
                    } else {
                        $error = 'Не удалось обновить дату поднятия заявки по неизвестной причине.';
                    }

                    throw new \DomainException($error);

                }

                $comment = 'Успешно';

            } else {

                $comment = "Заявка в статусе \"{$this->internalStatusName()}\"";

            }

            $this->link('liftLogs', new RequestLiftLog([
                'lift_at'   => $schedule->lift_at,
                'lifted_at' => $lifted_at,
                'comment'   => $comment
            ]));

            $schedule->delete();

        });

    }


}

Валидация AR здесь используется для проверки корректности данных правилам БД (а не для формы), чтобы туда что-попало не записалось. Это позволяет делать меньше VO, использовать скалярные типы. Вообще привычка на save() всегда такие проверки делать.

Под кодом, отвечающим за генерацию SQL-запросов имеется ввиду вызовы save(), link(), которые генерируют и выполняют sql-запросы.
Вот именно этот код можно прекрасно вынести в отдельный сервис. Сущность от такого перегружается, зачем этому быть в сущности? По сути у нас сущность начинает выполнять ещё и роль фабрики, создавая RequestLiftLog.
anton_z писал(а): 2019.08.15, 02:34 Тут я согласен с @ElisDN, такому место в сущностях. Я бы почти также сделал, только у меня внутри метода были бы вызовы save()/update() и транзакция.
Тем не менее это совершенно не аргумент, т.к. всё приведённое ElisDN не должно находиться в сущностях, как и в приведённом Вами примере всё это вообще должно быть в сервисе. Просто аргументов по поводу того, что это должно быть в сущности я реально не увидел.
anton_z писал(а): 2019.08.15, 02:34 P.S. В целом по теме согласен со @skynin что php в оригинале больше годен для прямого общения с БД, чем для "синхронизации состояния" (flush) как с EnityManager. Это больше годно для сред, где процессы постоянно запущены, и то надо пробовать. Я и на C++ и на Java также как в примере делал, правда опыта у меня в этих средах маловато.
С++ по сути своей ничем не отличается от PHP, разве что может всё хранить в памяти, но там другая цена этому. Сборка мусора руками, утечки памяти и т.п. В каждом ЯП приходится платить за его преимущества. Но. PHP прекрасно справляется со своими задачами. На нём можно писать всё то, о чём уже тут говорили. Момент лишь в том, что я вижу, как говорят о том, что сущность не должна ничего валидировать, лишнего в ней не должно быть, а в итоге к ней прилепляют тот функционал, который её усложняет. И так не только с сущностями. Это касается всего, что пишется под лозунгом "True Architect". По сути все умных книг поначитались и суют эту практику в массы, а практика то ни о чём.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение ElisDN »

BrusSENS писал(а): 2019.08.14, 22:07 Сколько говорили о том, что валидацией сущность не должна заниматься, а в итоге делаем всё наоборот. Это дело сервиса, но никак не сущности.
Это не валидация ввода из формы, а инкапсулированное поведение с контролем инварианта жизненного цикла объекта.
BrusSENS писал(а): 2019.08.14, 22:07 Ни о какой "слабосвязаности" про ооп не говорится, не нужно выдумывать. ООП - всего-лишь подход для представления всего в виде объектов.
Давайте вместо того, чтобы придумывать свои извращённые термины, вы пойдёте и прочитаете оригинальное определение ООП от его автора Алана Кея. О том, что под ООП подразумевается система с обменом сообщениямими между самодостаточными объектами, инкапсулирующими в себе все состояние и логику для избавления от расшаренного состояния и для уменьшения связности. Вот тогда и будем спорить с вами о реальном ООП, а не вами придуманном.
BrusSENS писал(а): 2019.08.15, 12:57 Тем не менее это совершенно не аргумент, т.к. всё приведённое ElisDN не должно находиться в сущностях, как и в приведённом Вами примере всё это вообще должно быть в сервисе. Просто аргументов по поводу того, что это должно быть в сущности я реально не увидел.
Как видим по определению - это аргумент. Обеспечение инкапсуляции и снижение связанности с другими классами.

ООП позволяет мне сделать самодостаточный объект, живущий своей жизнью и контролирующий своё состояние. Хранящий всё надёжно внутри и не позволяющий присвоить ерунду в публичное поле снаружи.

У вас же вместо объекта есть просто беззащитная сущность (структура) с состоянием без поведения и пачка сервисов (процедур) с поведением без состояния. И кто угодно может присвоить что угодно без всякого контроля. Это процедурное программирование на классах, которое к объектно-ориентированному никакого отношения не имеет.

Так что нравится выносить в сервисы - выносите. Только тогда не называйте это объектно-ориентированным кодом.
BrusSENS писал(а): 2019.08.14, 22:07 И паттерны придуманы не для создания "слабой связанности", а для решения определённых проблем при проектировании. Где у нас синглтон связанность уменьшает? Верно, нигде. Это всего лишь решение, для того, что бы объект класса существовал в единственном экземпляре.
Одиночка, фабрика, построитель - это порождающие паттерны, позволяющие сделать систему независимой от создания объектов. Отвязать от вызова конструктора. Вместо хардкорного создания нужного объекта через new мы его создаём или достаём из метода make() фабрики, build() построителя, copy() прототипа или instance() синглтона. А синглтон по сути является простой фабрикой с кешированием.

Структурные паттерны вроде декоратора и прокси как раз развязывают код, позволяя абсолютно незаметно модифицировать взаимодействие между объектами, внедряя прослойки между ними. Адаптер и фасад позволяют вообще не думать о стороннем объекте, полностью отвязав свой код от устройства сторонних компонентов.

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

Принципы SOLID выведены как рекомендации для написания слабосвязанных систем с разделением по изменяемым областям (S), с возможностью модификации без необходимости влазить внутрь (O), с соблюдением публичных контрактов (L) минимально необходимого размера (I) без завязки на реализацию (D).

Паттерны GRASP (общие шаблоны распределения ответственностей) целиком выведены именно для снижения Coupling между модулями и повышения Cohesion внутри модуля.

Как раз по принципу Information Expert из GRASP я изначально помещаю логику максимально внизу рядом с нужными ей данными. Метод makeBid прямо в сущности работает с её приватным состоянием. И мне не нужно открывать поля наружу для публичного доступа и искать, кто какое поле модифицирует. Если нужен какой-то сложный хелпер, то он передаётся в метод. Если же какой-то логике нужно управлять несколькими объектами А и B, то только она поднимается вверх в сервис С и оттуда дёргает A и B.

Так что практически все паттерны и принципы борются со связанностью, пытаясь развязать наш код: разделяют по ответственностям, выносят меняющиеся фрагменты, прячут сложные вещи, снижают привязку к сторонним системам, защищают от жёстких привязок модулей друг на друга, разбивают на слабосвязанные подсистемы.
BrusSENS писал(а): 2019.08.14, 14:06 Паттернизм - бич сегодняшнего PHP. Вроде паттерны знают, вроде применяют, вроде об архитектуре размышляют.
Как видим, самый распространённый мегабич - это непонимание ООП как с вами в примере выше. И из него уже следуют остальные.
Аватара пользователя
BrusSENS
Сообщения: 565
Зарегистрирован: 2012.07.26, 06:51
Откуда: Новороссийск
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение BrusSENS »

ElisDN писал(а): 2019.08.15, 15:21 Это не валидация ввода из формы, а инкапсулированное поведение с контролем инварианта жизненного цикла объекта.
Называть можно как угодно, но у вас производится валидация (проверка данных на соответствие и допустимость их дальнейшего использования).
ElisDN писал(а): 2019.08.15, 15:21 Давайте вместо того, чтобы придумывать свои извращённые термины, вы пойдёте и прочитаете оригинальное определение ООП от его автора Алана Кея. О том, что под ООП подразумевается система с обменом сообщениямими между самодостаточными объектами, инкапсулирующими в себе все состояние и логику для избавления от расшаренного состояния и для уменьшения связности. Вот тогда и будем спорить с вами о реальном ООП, а не вами придуманном.

Как видим по определению - это аргумент. Обеспечение инкапсуляции и снижение связанности с другими классами.

ООП позволяет мне сделать самодостаточный объект, живущий своей жизнью и контролирующий своё состояние. Хранящий всё надёжно внутри и не позволяющий присвоить ерунду в публичное поле снаружи.

У вас же вместо объекта есть просто беззащитная сущность (структура) с состоянием без поведения и пачка сервисов (процедур) с поведением без состояния. И кто угодно может присвоить что угодно без всякого контроля. Это процедурное программирование на классах, которое к объектно-ориентированному никакого отношения не имеет.

Так что нравится выносить в сервисы - выносите. Только тогда не называйте это объектно-ориентированным кодом.
Читаем теперь внимательно
и перестаём приводить в аргументы из статей некачественного хостера на хабре. PHP не единственный ЯП. Может C++ тоже многие разработчики не понимают суть ООП?
ElisDN писал(а): 2019.08.15, 15:21 Так что практически все паттерны и принципы борются со связанностью, пытаясь развязать наш код: разделяют по ответственностям, выносят меняющиеся фрагменты, прячут сложные вещи, снижают привязку к сторонним системам, защищают от жёстких привязок модулей друг на друга, разбивают на слабосвязанные подсистемы.
Это ваши мысли сугубо личные. О том, что паттерны созданы для того, что бы сделать систему слабосвязанной - бред сивой кобылы. Нигде ничего подобного не говорится и намёков нет. Монолит тоже может быть качественным. А паттерны - всего лишь решения для определённого круга обыденных проблем, но никак не для борьбы со связанностью.
ElisDN писал(а): 2019.08.15, 15:21 Как видим, самый распространённый мегабич - это непонимание ООП как с вами в примере выше. И из него уже следуют остальные.
А с чего Вы решили, что я понимаю неверно принципы ООП, а не Вы? Получается вот и аргумент. Собственное ЧСВ, ничего более. Аргументов nullptr. Вижу, что разговор зашёл в никуда и, думаю, что лучше каждый останется при своём мнении.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение ElisDN »

BrusSENS писал(а): 2019.08.15, 19:15 Называть можно как угодно, но у вас производится валидация (проверка данных на соответствие и допустимость их дальнейшего использования).
Называйте как угодно. Хоть валидацией, хоть прекондишенами, хоть ещё как-нибудь. Но всё равно это реализация бизнес-правил. Но тогда кто вам сказал, что в объекте такой валидации быть не должно?
BrusSENS писал(а): 2019.08.15, 19:15 Читаем теперь внимательно
и перестаём приводить в аргументы из статей некачественного хостера на хабре.
Не нравится перевод цитат на хабре - смотрите оригинал и читайте ответ самого Кея.
BrusSENS писал(а): 2019.08.15, 19:15 PHP не единственный ЯП. Может C++ тоже многие разработчики не понимают суть ООП?
Если считаете википедию достоверным источником с определением от Ганди Буча, то промотайте до раздела Сложности определения и увидите ответ:
ООП имеет уже более чем сорокалетнюю историю, но, несмотря на это, до сих пор не существует чёткого общепринятого определения данной технологии. Основные принципы, заложенные в первые объектные языки и системы, подверглись существенному изменению (или искажению) и дополнению при многочисленных реализациях последующего времени.
Так что хоть какое современное определение читайте, но изначально ООП придумывался для обмена сообщениями и работал идеально хоть по той же Actor Model в Smalltalk.

А PHP или C++ - не важно, как написано ниже. ООП работает и в JavaScript без классов (которые появились в 2015 чисто как синтаксический сахар) на утиной типизации, инкапсуляции замыканиями и прототипном наследовании. И также организуется в Lisp без классов на функциях с мутаторами.
BrusSENS писал(а): 2019.08.15, 19:15 Это ваши мысли сугубо личные. О том, что паттерны созданы для того, что бы сделать систему слабосвязанной - бред сивой кобылы. Нигде ничего подобного не говорится и намёков нет. Монолит тоже может быть качественным. А паттерны - всего лишь решения для определённого круга обыденных проблем, но никак не для борьбы со связанностью.
Ага, конечно, не говорится. Заходим в вашу любимую Википедию и читаем сивую кобылу:
Порождающие шаблоны (англ. Creational patterns) — шаблоны проектирования, которые абстрагируют процесс инстанцирования. Они позволяют сделать систему независимой от способа создания, композиции и представления объектов.
Посредник (англ. Mediator) — поведенческий шаблон проектирования, обеспечивающий взаимодействие множества объектов, формируя при этом слабую связанность и избавляя объекты от необходимости явно ссылаться друг на друга.
Какие-то паттерны придуманы для этого явно. В других мы получаем уменьшение связанности неявно как бонус.
BrusSENS писал(а): 2019.08.15, 19:15 А с чего Вы решили, что я понимаю неверно принципы ООП, а не Вы? Получается вот и аргумент. Собственное ЧСВ, ничего более. Аргументов nullptr. Вижу, что разговор зашёл в никуда и, думаю, что лучше каждый останется при своём мнении.
Не используете инкапсуляцию, называете структуры без поведения объектами, путаете клиентскую валидацию с соблюдением инварианта. Это никак не вяжется с:
В центре ООП находится понятие объекта. Объект — это сущность, которой можно посылать сообщения и которая может на них реагировать, используя свои данные. Объект — это экземпляр класса. Данные объекта скрыты от остальной программы. Сокрытие данных называется инкапсуляцией.
Так что оставайтесь при своём мнении сколько угодно долго. Реальность от этого не изменится.
Аватара пользователя
BrusSENS
Сообщения: 565
Зарегистрирован: 2012.07.26, 06:51
Откуда: Новороссийск
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение BrusSENS »

ElisDN писал(а): 2019.08.15, 23:43 Называйте как угодно. Хоть валидацией, хоть прекондишенами, хоть ещё как-нибудь. Но всё равно это реализация бизнес-правил. Но тогда кто вам сказал, что в объекте такой валидации быть не должно?
А кто Вам сказал, что должна быть? Сущность, по своему определению не должна валидировать данные, разве не так?
ElisDN писал(а): 2019.08.15, 23:43 Не нравится перевод цитат на хабре - смотрите оригинал и читайте ответ самого Кея.
Кей один из начинателей, не более. Да, многое внёс в понятие ООП, но есть и другие, кто говорит иначе.
ElisDN писал(а): 2019.08.15, 23:43 Если считаете википедию достоверным источником с определением от Ганди Буча
Гради Буч, на минутку.
ElisDN писал(а): 2019.08.15, 23:43
ООП имеет уже более чем сорокалетнюю историю, но, несмотря на это, до сих пор не существует чёткого общепринятого определения данной технологии. Основные принципы, заложенные в первые объектные языки и системы, подверглись существенному изменению (или искажению) и дополнению при многочисленных реализациях последующего времени.
Так что хоть какое современное определение читайте, но изначально ООП придумывался для обмена сообщениями и работал идеально хоть по той же Actor Model в Smalltalk.

А PHP или C++ - не важно, как написано ниже. ООП работает и в JavaScript без классов (которые появились в 2015 чисто как синтаксический сахар) на утиной типизации, инкапсуляции замыканиями и прототипном наследовании. И также организуется в Lisp без классов на функциях с мутаторами.
Об этом Вам и пытаюсь донести. Нет чёткого понимания, что такое true ООП. Посему и имею своё мнение, что сущность не должна проверять/валидировать корректность данных внутри себя. Или Ваше мнение только верное? Тогда у Вас ЧСВ, что поделать.
ElisDN писал(а): 2019.08.15, 23:43 Ага, конечно, не говорится. Заходим в вашу любимую Википедию и читаем сивую кобылу:
Какие-то паттерны придуманы для этого явно. В других мы получаем уменьшение связанности неявно как бонус.
Верно, но...
Говорится про некоторые, но никак не про все, как Вы утверждали ранее.
ElisDN писал(а): 2019.08.15, 23:43 Не используете инкапсуляцию, называете структуры без поведения объектами, путаете клиентскую валидацию с соблюдением инварианта. Это никак не вяжется с:
В центре ООП находится понятие объекта. Объект — это сущность, которой можно посылать сообщения и которая может на них реагировать, используя свои данные. Объект — это экземпляр класса. Данные объекта скрыты от остальной программы. Сокрытие данных называется инкапсуляцией.
Вполне вяжется. Написано же, сущность может реагировать, используя свои данные. Свои, а не обрабатывая другие сущности.
ElisDN писал(а): 2019.08.15, 23:43 Так что оставайтесь при своём мнении сколько угодно долго. Реальность от этого не изменится.
Реальность чья? Ваша? Конечно не изменится. ЧСВ тяжело лечить в общем. Вместо конкретики от Вас увидел лишь обобщённо один смысл: "Мой ООП верный. Я всё понимаю правильно, а вы, смертные, лучше слушайте, что я говорю.".

Посему давайте прекратим этот бессмысленный балаган, ибо ничего толкового из этого разговора не получается.
Native Web - небольшой блог о веб разработке (временно на ремонте)
Режим обслуживания сайта для Yii 2.x.x
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение ElisDN »

BrusSENS писал(а): 2019.08.17, 01:10 А кто Вам сказал, что должна быть?
Все определения ООП (старые и новые) включают в себя инкапсуляцию для обеспечения соблюдения инварианта объекта. Вынос проверок наружу дважды ломает инкапсуляцию и позволяет нарушить инвариант. Сущность становится несамостоятельной, так как теперь не может работать полноценно в одиночку без сервиса.
BrusSENS писал(а): 2019.08.17, 01:10 Сущность, по своему определению не должна валидировать данные, разве не так?
Скопируете сюда своё определение без инкапсуляции и валидации бизнес-правил – посмотрим.
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: QueryBuilder и AR в отдельном пакете?

Сообщение skynin »

ElisDN писал(а): 2019.08.17, 09:32 Все определения ООП (старые и новые) включают в себя инкапсуляцию для обеспечения соблюдения инварианта объекта. Вынос проверок наружу дважды ломает инкапсуляцию и позволяет нарушить инвариант. Сущность становится несамостоятельной, так как теперь не может работать полноценно в одиночку без сервиса.
холивары про правильное/неправильное ООП обычно вызваны путаницей в головах о букве П.
В одних случаях она расшифровывается как Проектирование, а в других как Программирование.
Причем, незаметно для себя эту путаницу нередко генерирует один и тот же человек.

Например в одном предложении пишет о программировании
"для обеспечения соблюдения инварианта объекта"
а потом уже о проектировании
"Сущность становится несамостоятельной"

Объект в ЯП, и сущность в домене - тождественные понятия, синонимы?

Для джунов у меня есть краткое замечание для напряжения мозга о разнице между ОО проектированием, и ОО программированием:

Представть язык программирования, у которого нет ни классов, ни объектов, а только интерфейсы. (впрочем уже представлять не сложно, берем Go)
И вот, для такого языка мы можем спокойно проектировать в ОО парадигме, но не можем и ОО строчки написать.

Итак, вам вопрос, к чему относится:
так как теперь не может работать полноценно в одиночку без сервиса - к проектированию (доменной области) или к программированию (реализации)?

И, случайно вышло что наткнулся на коменты:
Sam (ну который Dark)
- Как с высокими нагрузками справляется Doctrine ORM?
По сравнению с Yii — плохо.
- С Doctrine у меня такого опыта нет, но раз нужно хорошо знать SQL, EXPLAIN, то я так понимаю, что очень много SQL пишут руками, не полагаясь на QueryBuilder?
Индексы часто забывают плюс доктрина иногда чудит с построением запросов и да, приходится руками переделывать.
Symfony, по сравнению с Yii, работает медленней, но, в общем, терпимо.

C Doctrine я не работал. Но очень плотно работал с Hibernate, чтобы уверенно сказать
Такие ORMы нужны если пытаться отождествить ОО проектирование и ОО программирование, стереть разницу между ними.
И это - можно сделать, и будет полезно... при многих и всяческих если :)

Упоротость начинается тогда, когда сторонник, поклонник не понимает что "серебрянной пули" не существует. и выдает свои вкусы, предпочтения за единственно верный путь, трактовку
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение samdark »

ElisDN
Все определения ООП (старые и новые) включают в себя инкапсуляцию для обеспечения соблюдения инварианта объекта.
Чтиво в тему: https://martinfowler.com/ieeeSoftware/p ... iation.pdf
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: QueryBuilder и AR в отдельном пакете?

Сообщение ElisDN »

skynin писал(а): 2019.08.17, 12:15 холивары про правильное/неправильное ООП обычно вызваны путаницей в головах о букве П.
В одних случаях она расшифровывается как Проектирование, а в других как Программирование.
Причем, незаметно для себя эту путаницу нередко генерирует один и тот же человек.
Хоть ООP, хоть OOD - основополагающая OO суть не меняется. Любое ОО - это про объекты, а не про class или extends.
skynin писал(а): 2019.08.17, 12:15 Для джунов у меня есть краткое замечание для напряжения мозга о разнице между ОО проектированием, и ОО программированием: Представть язык программирования, у которого нет ни классов, ни объектов, а только интерфейсы. (впрочем уже представлять не сложно, берем Go) И вот, для такого языка мы можем спокойно проектировать в ОО парадигме, но не можем и ОО строчки написать.
В Go и Pascal класс с состоянием и поведением синтаксически описывается структурой + пачкой методов к ней. В Go наследование реализуется интерфейсами.

В JavaScript класс с состоянием и поведением описывается функцией с объявлением полей и методов внутри. Наследование реализуется прототипами.

А далее по ОО-строчкам разницы никакой:

Код: Выделить всё

// Go
user := User{Email: "user@app.test"}
user.Activate()

// JS
user = new User('user@app.test')
user.activate()

// PHP
user = new User('user@app.test');
user->activate();
Класс - декларация, описывающая состояние и поведение. Объект - каждый экземпляр, по ней порождённый. Ни в Go, ни в классическом JS слов class и extends нет, но классы и объекты есть. Просто в разных языках они синтаксически реализуются и называются по-разному.

А если думаете что классы - это про слово class и считаете что Go - это "язык программирования, у которого нет ни классов, ни объектов, а только интерфейсы" то ССЗБ.

Это всё равно, что считать, что в PHP нет переменных, так как нет слова var, а в Java нет функций, так как нет слова function.

Продвинутый джун должен вам об этом рассказать.
skynin писал(а): 2019.08.17, 12:15 Итак, вам вопрос, к чему относится:
так как теперь не может работать полноценно в одиночку без сервиса - к проектированию (доменной области) или к программированию (реализации)?
Штука, к которой есть поля, но нет поведения (структура или ассоциативный массив) ни в OOP, ни в OOD объектом не является.
skynin писал(а): 2019.08.17, 12:15 Как с высокими нагрузками справляется Doctrine ORM?
По сравнению с Yii — плохо.
Если ORM применять по назначению для доставания и сохранения доменных объектов, то никаких проблем нет. Если пытаться на ORM костылить листинги в UI, то опять ССЗБ.
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: QueryBuilder и AR в отдельном пакете?

Сообщение skynin »

-- Любое ОО - это про объекты
только объектом можно сделать как "существительное" так и "глагол"

ООП не навязывает способ декомпозиции - как при моделировании, так и при написании кода

Кубик рубика можно описать как объект с поведением и состоянием, а можно описать клеточки и стороны и правила их взаимодействия, чтобы сэмулировать "кубик рубика"

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

-- В Go и Pascal, JavaScript ,
это название языков программирования.

то есть П расшифровываем как программирование.

-- А если думаете что классы, ... Это всё равно, что считать
не надо телепатировать. тем более в таком ключе - вы кретин что-ля?

Точно известно - если один считает другого кретином - то кто-то из них точно кретин. может и обое конечно :)

классы - это когда П - проектирование

-- Штука, к которой есть поля, но нет поведения (структура или ассоциативный массив) ни в OOP, ни в OOD объектом не является.
Конечно.
Только еще раз
объект(в ЯП) и сущность(домена) - не синонимы никак.

-- Если ORM применять по назначению для доставания и сохранения доменных объектов
а это уже П - проектирование - должен ли доменный объект сохранять свое состояние персистентно, или не должен.

В реализациях Smalltalk это происходило автоматически.
И никаких ORMов не нужно было.

В этом то и была его сила, а не только в концепции - объекты посылают друг другу сообщения.

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

в таких проектах да, нет проблем при использовании ORM "по назначению для доставания и сохранения доменных объектов"
нет таких проблем и у архитекторов, аналитиков, которые не пишут код.

Я же видел обычно как реальные проблемы приводили в проектах к дрейфу от "просто доставания и сохранения доменных объектов" в сторону выделения сервисов, то есть выноса управления состоянием из доменных объектов.
и, как уже писал, вообще перенос управлением состоянием, в сторону хранимых процедур на сервере БД.

наоборот - как-то не припомню.
как-то не хватает фантазии представить что - выгоднее перенести управление состоянием доменных объектов из ХП или сервисов в сами эти объекты. на старте то так и было, что же потом происходит?
а потом третье П - практика.
когда оказывается что абстракции текут, компьютеры обладают конечным быстродействием, и т.д.

в теории же да, проблем нет :)

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

причем упор то в этом утверждении на "несамостоятельность" как некий грех, дефект.
то есть - уход уже вообще в философскую плоскость, а не прагматично-инженерную

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

даже у вас - если доменный объект весь такой самостоятельный - то зачем же ему ORM?
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Ответить