DDD: Как правильно работать с контекстами ?

  • Автор темы Автор темы Gutsy
  • Дата начала Дата начала
цена это функция
Есть разные аспекты одних и тех же понятий на естественном языке. Бизнесовый, философский, потребительский, etc. Поэтому просто выкидывать такие определения без привязки к контексту — это сотрясать воздух.
 
цена это некая функция которая зависит оп продавца, покупателя, количества и момента времени. iphone7 у разных продавцов для разных людей стоит по разному, мне как простому смертному 700 в магазине А, тебе как постоянному покупателю за 650 в магазине А, а ему как мужу дочери двоюродного брата продавца в магазина А по закупочной.

если продали товар за 42, придется отчитаться перед поставщиком, почему 42. нужно найти ту самую id цены в которой указаны условия.
 
Зачем тебе делать разделение на domain и persistence models (то, что ты называешь «моделью» и «сущностью» соответственно)? Doctrine тоже без проблем может оперировать id-шниками.
Есть у нас в системе такая штука, как фотографии отеля. Они имеют какие-то метаданные(название, описание, приоритет, ...) и сам файл. Метаданные хранятся в MySQL, а вот файлы в мускуле хранить идея плохая - поэтому мы выбрали GridFS(но на самом деле не важно, хоть просто в FS).
Т.е., получается, что у нас доменная модель фотографии отеля мапится уже на два разных хранилища.
Таких примеров в системе будет много, где то будут агрегаты, часть которых проще грузить из кэша, например...

З.Ы.: мы с @Gutsy над одним проектом работаем)
 
Если доктриновские entities использовать как persistence models, то надо уж мапить сразу весь aggregate root целиком. А с таким подходом, по-моему, проще оставить от доктрины один только квери билдер и делать "ручной датамаппер".
Вот, именно к ручному датамаперу мы и пришли. Попробовали сделать конвертацию сущностей доктрины в доменные модели и агрегаты прямо в репозитории - ничего хорошего не вышло... ((

Может есть у кого опыт таких извращений?) Дайте посмотреть на реализацию такого "датамапера", плиз
 
если продали товар за 42, придется отчитаться перед поставщиком, почему 42. нужно найти ту самую id цены в которой указаны условия.
Я боюсь, что тут просто подобрана ужасная терминология. Продали по $42 — это и есть цена. А подробности формирования цены можно было бы узнать, например, из offer'а. И называть это «ценой» для меня по меньшей мере странно.
 
Есть у нас в системе такая штука, как фотографии отеля. Они имеют какие-то метаданные(название, описание, приоритет, ...) и сам файл. Метаданные хранятся в MySQL, а вот файлы в мускуле хранить идея плохая - поэтому мы выбрали GridFS(но на самом деле не важно, хоть просто в FS).
Т.е., получается, что у нас доменная модель фотографии отеля мапится уже на два разных хранилища.
Сам файл? В смысле blob? Он в виде свойства у модели что ли?

Почему в модели не может быть просто имя файла или id фотографии?
 
Сам файл? В смысле blob? Он в виде свойства у модели что ли?

Почему в модели не может быть просто имя файла или id фотографии?
Да, сам файл в свойстве(по факту это конечно же ссылка на "ленивый" объект). Почему так?
1. Потому что файл - неотъемлемое свойство модели и модель без него не является валидной.
2. В контроллере отсутствуют операции по поискам файла в каком-либо хранилище, объект в свойстве файла описывает некий интерфейс, который умеет файл представлять в виде строки или ресурса. Таким образом мы в любой момент можем заменить хранилище файлов и не переписывать все контроллеры.

И сейчас это дело организовано через кастомный тип доктрины, DM туда просовывается в билдере бандла:
PHP:
class UploadMongoType
{
   /** @var DocumentManager */
    protected $dm;
   ....

    /**
     * @param mixed $value
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
     * @return null
     * @throws \Doctrine\DBAL\Types\ConversionException
     */
    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        if (empty($value)) {
            return null;
        }

        if ($value instanceof UploadMongo) {
            if ($this->dm->getUnitOfWork()->getDocumentState($value) === UnitOfWork::STATE_NEW) {
                $this->dm->persist($value);
            }
            $this->dm->flush();

            return $value->getId();
        }

        throw ConversionException::conversionFailed($value, self::NAME);
    }

    /**
     * @param mixed $value
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
     * @return null
     */
    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        if (empty($value)) {
            return null;
        }

        return $this->dm->getReference(UploadMongo::class, $value);
    }
}

Оно работает, но выглядит как костыль. Хочется именно отделить доменные Модели от ОРМ.
 
У вас содержимое файла в бизнес логике никак не участвует. И не надо это тащить туда. Вытаскиваете файл только на фронте и все. Свойства с идентификатором(именем) файла - достаточно.
 
даже если тебе предложениями легче думать, вопрос "какое из предложений" остался
Я не знаю какие там у тебя вопросы остались, но я вёл речь про терминологию, которая тебя, судя по всему, как раз безразлична.
 
Это значит, что цены $42 и $42 — это разные цены
да, по разным договорам, предложениям как хочешь, значение одно а цена как единица с указанием "что за цена" разная!
но я вёл речь про терминологию
намешал все до кучи, не поняв смысла.
 
Да, сам файл в свойстве(по факту это конечно же ссылка на "ленивый" объект). Почему так?
1. Потому что файл - неотъемлемое свойство модели и модель без него не является валидной.
Это культ Карго. Как уже отметили, это свойство никак в бизнес-логике не участвует, бессмысленно его туда тащить.

Я очень рекомендую попробовать записывать события в модели: https://phpclub.ru/talk/threads/Как...trine-analogue-ручками-etc.82411/#post-747858
Тогда станет понятно, что главное в сущности — это именно отклик в виде события, а не то, какие там внутри свойства. И я боюсь, что наличие blob'а с изображением в сущности никак на отклик влиять не будет совершенно.

Второй момент, на который я хочу обратить внимание — это разделение чтения и записи (CQRS). Вот это рассуждение на тему того какие свойства могут понадобится в момент чтения будет очень сильно мешать для реализации чистой модели.
 
У вас содержимое файла в бизнес логике никак не участвует. И не надо это тащить туда. Вытаскиваете файл только на фронте и все. Свойства с идентификатором(именем) файла - достаточно.
т.е. вот такая логика?
- при добавлении фотки - мы этот файл где-то в контроллере или обработчике команды записываем в GridFS - получаем id и создаем модель фотографии уже с этим id.
- при чтении фотки - опять же в контроллере мы идем в GridFS, ищем файл, генерируем линк на него - показываем
- при удалении фотки - в контроллере или обработчике команды удаляем файл из GridFS и модель.

Получается что просто удаления модели недостаточно чтобы были соблюдены все бизнес-правила. Бизнес правило просит удалять фотографию вместе с файлом.. а мы эту логику выносим из домена?
Или бизнес ничего не знает о файлах - для него только фотка удаляется, а файл - это уже детали реализации, так?
 
Второй момент, на который я хочу обратить внимание — это разделение чтения и записи (CQRS). Вот это рассуждение на тему того какие свойства могут понадобится в момент чтения будет очень сильно мешать для реализации чистой модели.
вот, а как же в этом случае мапить read и write модели на одни и те же данные? или read модель строить из write модели, а мапить только её?
 
Да. Вся работа с файлами - инфраструктура. Конретно в бизнес операциях содержимое файла никак не влияет. Все эти гридфс и с3 - не должны залазить в модель. Она должна быть чиста и невинна. И не думать о суровых реалиях.
 
@camohob, потому что сущность фотография отеля на логику и не влияет особо. Ну может при рпсчете рейтингов каких нибудь их количество будет влиять. Это для сайта какойто смысл они имеют. Но не для домена.
 
А можно какие-то реальные примеры из вашего домена, происходящие с отелем, помимо «добавить», «посмотреть», «удалить»? Потому что здесь не нужен никакой DDD, если всё сводится к этому.
 
Сверху